Source file inclusion
在当前源文件的指令所在行之后立即包含其他源文件。
目录 |
语法
#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 。
|
如果由
头文件名
(即
|
(自 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++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; } // 等等 }; #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 |
若在
q-字符序列
或
h-字符序列
中出现
类似转义序列的结构则行为未定义 |
改为有条件支持 |
参见
| C++ 标准库头文件列表 | |
|
C 文档
关于
源文件包含
|