Включение исходного файла
Включает другой исходный файл в текущий исходный файл в строке сразу после директивы.
Содержание |
[править]Синтаксис
#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 1template<class T>using optional_t =std::optional<T>;#elif __has_include(<experimental/optional>)# include <experimental/optional># define has_optional -1template<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";elseif(has_optional <0)std::cout<<"<experimental/optional> присутствует\n";elsestd::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 по Включение исходного файла |