Пространства имён
Варианты
Действия

Включение исходного файла

Материал из cppreference.com
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений(до C++17*)
Спецификатор noexcept(C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype(C++11)
auto(C++11)
alignas(C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr(C++11)
Определяемые пользователем(C++11)
Утилиты
Атрибуты(C++11)
Types
Объявление typedef
Объявление псевдонима типа(C++11)
Casts
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
Выделение памяти
Классы
Свойства функции класса
Специальные функции-элементы
Шаблоны
Разное
 
 

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

Содержание

[править]Синтаксис

#include <последовательность-h-символов>новая-строка (1)
#include "последовательность-q-символов"новая-строка (2)
#includepp-токеныновая-строка (3)
__has_include("последовательность-q-символов")
__has_include(<последовательность-h-символов>)
(4) (начиная с C++17)
__has_include(строковый-литерал)
__has_include(<h-pp-токены>)
(5) (начиная с C++17)

Любые маркеры предварительной обработки (макроконстанты или выражения) разрешены в качестве аргументов для #includeи __has_include(начиная с C++17), пока они расширяются до последовательности символов, окружённой <> или "".

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

[править]Объяснение

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

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

importимя-заголовка;новая-строка

(начиная с 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 по Включение исходного файла
close