源文件包含
将其他源文件包含到当前源文件中紧随指令之后的一行。
语法
#include < h字符序列 > 换行
|
(1) | ||||||||
#include " q字符序列 " 换行
|
(2) | ||||||||
#include 记号序列 换行
|
(3) | ||||||||
__has_include ( " q字符序列 " ) __has_include ( < h字符序列 > )
|
(4) | (C++17 起) | |||||||
__has_include ( 字符串字面量 ) __has_include ( < h记号序列 > )
|
(5) | (C++17 起) | |||||||
换行 | - | 换行符 |
h字符序列 | - | 一个或多个 h字符,并且其中以下内容的出现受条件性支持:
|
h字符 | - | 源字符集 (C++23 前)翻译字符集 (C++23 起) 除了换行符和 > 以外的任何成员
|
q字符序列 | - | 一个或多个 q字符,并且其中以下内容的出现受条件性支持:
|
q字符 | - | 源字符集 (C++23 前)翻译字符集 (C++23 起) 除了换行符和 " 以外的任何成员
|
记号序列 | - | 一个或多个预处理记号 |
字符串字面量 | - | 一个字符串字面量 |
h记号序列 | - | 一个或多个除了 > 以外的预处理记号
|
说明
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:在已经包含相同文件(文件的身份以操作系统指定的方式确定)的时候禁止处理该文件。
如果 h字符序列 或 q字符序列 中包含了类似转义序列的序列,那么根据实现可能会导致错误,被处理为转义序列对应的字符,或者具有完全不同的含义。
结果是 1 的 __has_include
只表明存在有指定名称的头或源文件。它并不意味着包含该头或源文件时不会导致错误,或它会包含任何有意义的内容。例如在同时支持 C++14 和 C++17 模式(并在其 C++14 模式作为一项遵从标准的扩展而提供 __has_include)的 C++ 实现上,__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 # 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++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 787 | C++98 | 如果 h字符序列 或 q字符序列 中包含了类似转义序列的序列,那么行为未定义 | 改为受条件性支持 |
参阅
C++ 标准库头文件列表 |