Namespaces
Variants

Source file inclusion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Включает другой исходный файл в текущий исходный файл на строке, непосредственно следующей за директивой.

Содержание

Синтаксис

#include < h-char-sequence > new-line (1)
#include " q-char-sequence " new-line (2)
#include pp-tokens new-line (3)
__has_include ( " q-char-sequence " )
__has_include ( < h-char-sequence > )
(4) (начиная с C++17)
__has_include ( string-literal )
__has_include ( < h-pp-tokens > )
(5) (начиная с C++17)
1) Ищет заголовок, однозначно идентифицируемый с помощью h-char-sequence и заменяет директиву всем содержимым этого заголовка.
2) Выполняет поиск исходного файла, идентифицированного q-char-sequence и заменяет директиву всем содержимым исходного файла. Может переключиться на (1) и обрабатывать q-char-sequence как идентификатор заголовка.
3) Если ни (1) ни (2) не совпадают, pp-tokens подвергнутся макроподстановке. Директива после подстановки будет повторно проверяться на соответствие с (1) или (2) .
4) Проверяет, доступен ли заголовочный или исходный файл для включения.
5) Если (4) не совпадает, h-pp-tokens подвергаются макроподстановке. Директива после подстановки будет снова проверяться на соответствие с (4) .
new-line - Символ новой строки
h-char-sequence - Последовательность одного или более h-char ов, где появление любого из следующих символов условно поддерживается с семантикой, определяемой реализацией:
  • символ '
  • символ "
  • символ \
  • последовательность символов //
  • последовательность символов /*
h-char - Любой элемент исходного набора символов (до C++23) трансляционного набора символов (начиная с C++23) кроме символа новой строки и >
q-char-sequence - Последовательность одного или более q-char ов, где появление любого из следующих символов условно поддерживается с семантикой, определяемой реализацией:
  • символ '
  • символ \
  • последовательность символов //
  • последовательность символов /*
q-char - Любой элемент исходного набора символов (до C++23) трансляционного набора символов (начиная с C++23) кроме символа новой строки и "
pp-tokens - Последовательность одного или более токенов препроцессора
string-literal - Строковый литерал
h-pp-tokens - Последовательность одного или более токенов препроцессора кроме >

Объяснение

1) Выполняет поиск в последовательности местоположений заголовка, однозначно идентифицируемого с помощью h-char-sequence , и заменяет эту директиву полным содержимым заголовка. Способ указания местоположений или идентификации заголовка определяется реализацией.
2) Вызывает замену этой директивы всем содержимым исходного файла, идентифицированного q-char-sequence . Указанный исходный файл ищется в определяемой реализацией манере.
Если этот поиск не поддерживается или если поиск завершается неудачей, директива обрабатывается повторно, как если бы она имела синтаксис (1) с идентичной содержащейся последовательностью (включая > символы, если таковые имеются) из исходной директивы.
3) Токены препроцессора после include в директиве обрабатываются так же, как в обычном тексте (т.е. каждый идентификатор, определённый в данный момент как имя макроса, заменяется своим списком замены токенов препроцессора).
Если директива, полученная после всех замен, не соответствует одной из двух предыдущих форм, поведение не определено.
Способ, которым последовательность препроцессорных токенов между < и > парой препроцессорных токенов или парой символов " объединяется в единый токен имени заголовка, определяется реализацией.
4) Заголовочный или исходный файл, определяемый h-char-sequence или q-char-sequence , ищется таким образом, как если бы эта последовательность препроцессорных токенов была pp-tokens в синтаксисе (3) , за исключением того, что дальнейшее макроподстановки не выполняются.
  • Если такая директива не удовлетворяет синтаксическим требованиям директивы #include , программа является некорректной.
  • В противном случае выражение __has_include вычисляется в 1 , если поиск исходного файла завершается успешно, и в 0 , если поиск завершается неудачно.
5) Эта форма рассматривается только в том случае, если синтаксис (4) не совпадает, и в этом случае токены препроцессора обрабатываются так же, как в обычном тексте.

Если заголовок, идентифицируемый header-name (т.е., < h-char-sequence > или " q-char-sequence " ), обозначает импортируемый заголовок, то определяется реализацией, заменяется ли #include директива препроцессора на директиву импорта вида

import header-name ; new-line

(since C++20)

__has_include может быть раскрыто в выражениях #if и #elif . Оно рассматривается как определенный макрос в #ifdef , #ifndef , #elifdef , #elifndef (начиная с C++23) и defined , но не может быть использовано в других местах.

Примечания

Типичные реализации производят поиск только в стандартных каталогах включения для синтаксиса (1) . Стандартная библиотека C++ и стандартная библиотека C неявно включены в эти стандартные каталоги включения. Стандартные каталоги включения обычно могут контролироваться пользователем через опции компилятора.

Назначение синтаксиса (2) — поиск файлов, не контролируемых реализацией. Типичные реализации сначала выполняют поиск в директории расположения текущего файла, затем переходят к (1) .

Когда файл включается, он обрабатывается на этапах трансляции 1-4, что может включать, рекурсивно, раскрытие вложенных #include директив, до определяемого реализацией предела вложенности. Чтобы избежать повторного включения одного и того же файла и бесконечной рекурсии, когда файл включает себя, возможно транзитивно, обычно используются заголовочные стражи : весь заголовок оборачивается в

#ifndef FOO_H_INCLUDED /* any name uniquely mapped to file name */
#define FOO_H_INCLUDED
// содержимое файла находится здесь
#endif

Многие компиляторы также реализуют нестандартную pragma #pragma once с аналогичным эффектом: она отключает обработку файла, если тот же файл (где идентичность файла определяется специфичным для ОС способом) уже был включен.

Последовательность символов, напоминающая escape-последовательность в q-char-sequence или h-char-sequence может привести к ошибке, быть интерпретирована как символ, соответствующий escape-последовательности, или иметь совершенно иное значение, в зависимости от реализации.

Результат __has_include равный 1 означает только то, что заголовочный или исходный файл с указанным именем существует. Это не означает, что при включении этого заголовочного или исходного файла не возникнет ошибка или что он будет содержать что-либо полезное. Например, в реализации C++, поддерживающей как режим C++14, так и режим C++17 (и предоставляющей __has_include в режиме C++14 в качестве соответствующего расширения), __has_include ( < optional > ) может быть 1 в режиме C++14, но фактически #include <optional> может вызвать ошибку.

Пример

#if __has_include(<optional>)
    #include <optional>
    #define has_optional 1
    template<class T>
    using optional_t = std::optional<T>;
#elif __has_include(<experimental/optional>)
    #include <experimental/optional>
    #define has_optional -1
    template<class T>
    using optional_t = std::experimental::optional<T>;
#else
    #define has_optional 0
    template<class V>
    class optional_t
    {
        V v{};
        bool has{};
    public:
        optional_t() = default;
        optional_t(V&& v) : v(v), has{true} {}
        V value_or(V&& alt) const&
        {
            return has ? v : alt;
        }
        // etc.
    };
#endif
#include <iostream>
int main()
{
    if (has_optional > 0)
        std::cout << "<optional> is present\n";
    else if (has_optional < 0)
        std::cout << "<experimental/optional> is present\n";
    else
        std::cout << "<optional> is not present\n";
    optional_t<int> op;
    std::cout << "op = " << op.value_or(-1) << '\n';
    op = 42;
    std::cout << "op = " << op.value_or(-1) << '\n';
}

Вывод:

<optional> is present
op = -1
op = 42

Отчёты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение как опубликовано Корректное поведение
CWG 787 C++98 поведение не определено, если escape-последовательность
присутствует в q-char-sequence или h-char-sequence
условно поддерживается

Смотрите также

Список заголовочных файлов стандартной библиотеки C++
Документация C для Подключение исходных файлов