Spec-Zone.ru › C++

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

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

Синтаксис

#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-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 - Последовательность одного или нескольких предварительных токенов, кроме >

Объяснение

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

(с 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API