命名空间
变体
操作

源文件包含

来自 cppreference.cn
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (在 C++17 中弃用*)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

将其他源文件包含到当前源文件中,指令紧随其后的行。

目录

[编辑] 语法

#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-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 - 一个或多个 预处理记号 的序列,除了 >

[编辑] 解释

1) 在实现定义的位置序列中搜索由 h-char-sequence 唯一标识的头文件,并将该指令替换为头文件的全部内容。位置的指定方式或头文件的标识方式是实现定义的。
2) 将该指令替换为由 q-char-sequence 标识的源文件的全部内容。命名的源文件以实现定义的方式进行搜索。如果不支持此搜索,或者搜索失败,则该指令将重新处理,就像它读取语法 (1) 一样,并带有来自原始指令的相同包含序列(如果存在 > 字符)。
3) 指令中 include 之后的预处理记号的处理方式与普通文本相同(即,当前定义为宏名称的每个标识符都将替换为其预处理记号的替换列表)。如果所有替换后产生的指令与前两种形式之一不匹配,则行为是未定义的。将 < 和 > 预处理记号对或一对 " 字符之间的预处理记号序列组合为单个头文件名称预处理记号的方法是实现定义的。
4) 头文件或源文件由 h-char-sequenceq-char-sequence 标识,搜索方式如同该预处理记号序列是语法 (3) 中的 pp-tokens,但不会执行进一步的宏展开。如果这样的指令不满足 #include 指令的语法要求,则程序是非良构的。如果源文件搜索成功,__has_include 表达式的计算结果为 1;如果搜索失败,则为 0
5) 仅当语法 (4) 不匹配时才考虑此形式,在这种情况下,预处理记号的处理方式与普通文本相同。

如果由 header-name(即 < h-char-sequence >" q-char-sequence ")标识的头文件表示可导入的头文件,则 #include 预处理指令是否被替换为 import 指令 的形式是实现定义的

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,效果类似:如果已包含同一文件(其中文件标识以操作系统特定的方式确定),它将禁用文件的处理。

q-char-sequenceh-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++ 标准。

DR 应用于 已发布行为 正确行为
CWG 787 C++98 如果转义序列在
q-char-sequenceh-char-sequence
它是有条件支持的

[编辑] 参见

C++ 标准库头文件列表
C 文档 关于 源文件包含