源文件包含
在指令之后立即将其他源文件包含到当前源文件中。
目录 |
[编辑] 语法
#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-char 序列,其中以下任何字符的出现是条件支持的,其语义是实现定义的
|
h-char | - | 除了换行符和 > 之外的 源字符集(C++23 前)翻译字符集(C++23 起) 的任何成员 |
q-char-sequence | - | 一个或多个 q-char 序列,其中以下任何字符的出现是条件支持的,其语义是实现定义的
|
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,具有类似的效果:如果同一文件(文件身份以操作系统特定方式确定)已被包含,则它会禁用对该文件的处理。
在 q-char-sequence 或 h-char-sequence 中类似于转义序列的字符序列可能会导致错误,被解释为与转义序列对应的字符,或者具有完全不同的含义,具体取决于实现。
__has_include
的结果为 1 仅表示存在具有指定名称的头文件或源文件。这并不意味着当包含头文件或源文件时不会导致错误或包含任何有用的内容。例如,在一个支持 C++14 和 C++17 模式的 C++ 实现上(并在其 C++14 模式下提供 __has_include 作为符合标准的扩展),__has_include(<optional>) 在 C++14 模式下可能为 1,但实际上 #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 template<class V> class optional_t { V v{}; bool has{}; public: optional_t() = default; optional_t(V&& v) : v(v), has{true} {} V value_or(V&& alt) const& { return has ? v : alt; } // etc. }; #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++ 标准。
缺陷报告 | 应用于 | 发布时的行为 | 正确的行为 |
---|---|---|---|
CWG 787 | C++98 | 如果转义序列类似于 在 q-char-sequence 或 h-char-sequence 中 |
它是条件支持的 |
[编辑] 参阅
C++ 标准库头文件列表 | |
C 文档 关于 源文件包含
|