Включение исходного файла
Включает другой исходный файл в текущий исходный файл в строке сразу после директивы.
Содержание |
[править] Синтаксис
#include < последовательность-h-символов > новая-строка
|
(1) | ||||||||
#include " последовательность-q-символов " новая-строка
|
(2) | ||||||||
#include pp-токены новая-строка
|
(3) | ||||||||
__has_include ( " последовательность-q-символов " ) __has_include ( < последовательность-h-символов > )
|
(4) | (начиная с C++17) | |||||||
__has_include ( строковый-литерал ) __has_include ( < h-pp-токены > )
|
(5) | (начиная с C++17) | |||||||
Любые маркеры предварительной обработки (макроконстанты или выражения) разрешены в качестве аргументов для #include
и __has_include
(начиная с C++17), пока они расширяются до последовательности символов, окружённой <
>
или "
"
.
новая-строка | — | Символ новой строки |
последовательность-h-символов | — | Последовательность из одного или нескольких символов h-символ, где появление любого из следующего поддерживается условно с семантикой, определяемой реализацией:
|
h-символ | — | Любой элемент исходного набора символов (до C++23)набора символов трансляции (начиная с C++23) кроме символа новой строки и > |
последовательность-q-символов | — | Последовательность из одного или нескольких q-символ, где появление любого из следующих элементов поддерживается условно с семантикой, определяемой реализацией:
|
q-символ | — | Любой элемент исходного набора символов (до C++23)набор символов трансляции (начиная с C++23) кроме символа новой строки и " |
pp-токены | — | Последовательность из одного или нескольких токенов предварительной обработки |
строковый-литерал | — | Строковый литерал |
h-pp-токены | — | Последовательность из одного или нескольких токенов предварительной обработки кроме > |
[править] Объяснение
include
в директиве обрабатываются так же, как и в обычном тексте (т.е. каждый идентификатор, определённый в настоящее время как имя макроса, заменяется своим замещающим списком токенов предварительной обработки). Если полученная после всех замен директива не соответствует ни одной из двух предыдущих форм, поведение не определено. Метод, с помощью которого последовательность токенов предварительной обработки между парой токенов предварительной обработки < и > или парой символов " объединяется в
токен предварительной обработки имени одного заголовка определяется реализацией.#include
, программа была бы некорректна. Выражение __has_include
оценивается как 1, если поиск исходного файла завершается успешно, и как 0, если поиск не удался.
Если заголовок, определяемый именем-заголовка (т.е.
|
(начиная с 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 /* любое имя, однозначно сопоставленное с именем файла */ #define FOO_H_INCLUDED // содержимое файла здесь #endif
Многие компиляторы также реализуют нестандартную pragma #pragma once с аналогичными эффектами: она отключает обработку файла, если этот файл (где идентификатор файла определяется в зависимости от ОС) уже включен.
Последовательность символов, похожая на управляющую последовательность в последовательности-q-символов или последовательности-h-символов, может привести к ошибке, интерпретируясь как символ, соответствующий управляющей последовательности, или иметь совершенно другое значение, в зависимости от реализации.
Результат __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 # 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> присутствует\n"; else if (has_optional < 0) std::cout << "<experimental/optional> присутствует\n"; else std::cout << "<optional> не присутствует\n"; optional_t<int> op; std::cout << "op = " << op.value_or(-1) << '\n'; op = 42; std::cout << "op = " << op.value_or(-1) << '\n'; }
Вывод:
<optional> присутствует op = -1 op = 42
[править] Смотрите также
Список заголовочных файлов Стандартной Библиотеки C++ | |
Документация C по Включение исходного файла
|