源文件包含
將其他源文件包含到當前源文件中緊隨指令之後的一行。
語法
#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記號序列 | - | 一個或多個除了 > 以外的預處理記號的序列
|
解釋
> 字符,如果存在)作為語法 (1) 中所需的序列。include 後面的預處理記號會按在正常文本中進行處理(即每個目前定義為宏名的標識符都會被替換為它的預處理記號替換列表)。< 和 > 之間或一對 " 字符之前的預處理記號序列合併為單個頭名預處理記號的方法由實現定義。- 如果剛才的語法 (3) 指令不滿足
#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 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
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> 存在\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++ 標準庫頭文件列表 | |
源文件包含的 C 文檔
|