Включение исходного файла
Включает другой исходный файл в текущий исходный файл в строке сразу после директивы.
Синтаксис
#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) |
| new-line | - | Символ новой строки |
| h-char-sequence | - | Последовательность одного или нескольких h-chars, где появление следующих символов условно поддерживается с реализацией определённой семантики:
|
| h-char | - | Любой член набора символов исходного текста(до C++23)символов набора перевода(с C++23) кроме новой строки и > |
| q-char-sequence | - | Последовательность одного или нескольких q-chars, где появление следующих символов условно поддерживается с реализацией определённой семантики:
|
| q-char | - | Любой член набора символов исходного текста(до C++23)символов набора перевода(с C++23) кроме новой строки и " |
| pp-tokens | - | Последовательность одного или нескольких предварительных токенов |
| string-literal | - | Строковая константа |
| h-pp-tokens | - | Последовательность одного или нескольких предварительных токенов, кроме > |
Объяснение
include в директиве обрабатываются так же, как и в обычном тексте (т.е., каждый идентификатор, в настоящее время определённый как имя макроса, заменяется его списком замещающих предварительных токенов). Если получившаяся после всех замещений директива не соответствует одному из двух предыдущих форм, поведение не определено. Способ объединения последовательности предварительных токенов между парой < и > предварительных токенов или парой " символов в один предварительный токен имени заголовка определяется реализацией.#include, программа некорректна. Выражение __has_include принимает значение 1, если поиск исходного файла успешен, и 0, если поиск не удался.| Если заголовок, идентифицируемый по header-name (т.е.,
| (с 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 // contents of the file are here #endif
Многие компиляторы также реализуют нестандартный pragma #pragma once с аналогичным эффектом: он отключает обработку файла, если тот же файл (где идентичность файла определяется способом, специфичным для ОС) уже был включён.
Последовательность символов, напоминающая escape-последовательность в q-char-sequence или h-char-sequence, может привести к ошибке, быть интерпретирована как символ, соответствующий escape-последовательности, или иметь совершенно иное значение, в зависимости от реализации.
Результат __has_include означает только то, что существует заголовочный файл или исходный файл с указанным именем. Это не означает, что заголовочный или исходный файл, при включении, не вызовут ошибку или будут содержать что-то полезное. Например, в реализации 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
# include <utility>
template<class V>
class optional_t
{
V v_{}; bool has_{false};
public:
optional_t() = default;
optional_t(V&& v) : v_(v), has_{true} {}
V value_or(V&& alt) const& { return has_ ? v_ : alt; }
/*...*/
};
#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 документация для Включение исходного файла |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/preprocessor/include