命名空间
变体
操作

条件包含

来自 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 起)
存储期说明符
初始化
表达式
替用表示法
字面量
布尔 - 整数 - 浮点
字符 - 字符串 - nullptr (C++11 起)
用户定义 (C++11 起)
工具
属性 (C++11 起)
类型
typedef 声明
类型别名声明 (C++11 起)
转型
内存分配
类专属函数属性
虚函数
override 说明符 (C++11 起)  
final 说明符 (C++11 起)
explicit (C++11 起)
static

特殊成员函数
模板
模板特化
形参包 (C++11 起)
杂项
 
预处理器
#if#ifdef#ifndef#else#elif#elifdef#elifndef#endif
(C++23 起)(C++23 起)
(C++23 起)
(C++11 起)
(C++26)
 

预处理器支持对源文件的部分进行条件编译。此行为由 #if#else#elif#ifdef#ifndef#elifdef#elifndef(自 C++23)#endif 指令控制。

内容

[编辑] 语法

#if 表达式
#ifdef 标识符
#ifndef 标识符
#elif 表达式
#elifdef 标识符 (自 C++23)
#elifndef 标识符 (自 C++23)
#else
#endif

[编辑] 解释

条件预处理块以 #if#ifdef#ifndef 指令开始,然后可选地包含任意数量的 #elif#elifdef#elifndef(自 C++23) 指令,然后可选地最多包含一个 #else 指令,并以 #endif 指令终止。任何内部条件预处理块都会被单独处理。

#if#ifdef#ifndef#elif#elifdef#elifndef(自 C++23)#else 指令中的每一个都控制代码块,直到第一个不属于任何内部条件预处理块的 #elif#elifdef#elifndef(自 C++23)#else#endif 指令。

#if#ifdef#ifndef 指令测试指定的条件(见下文),如果条件求值为真,则编译受控制的代码块。在这种情况下,后续的 #else#elifdef#elifndef(自 C++23)#elif 指令将被忽略。否则,如果指定的条件求值为假,则跳过受控制的代码块,并处理后续的 #else#elifdef#elifndef(自 C++23)#elif 指令(如果有)。如果后续指令是 #else,则无条件编译由 #else 指令控制的代码块。否则, #elif#elifdef#elifndef(自 C++23) 指令的行为就像它是 #if 指令一样:检查条件,根据结果编译或跳过受控制的代码块,并在后一种情况下处理后续的 #elif#elifdef#elifndef(自 C++23)#else 指令。条件预处理块由 #endif 指令终止。

[编辑] 条件求值

[编辑] #if, #elif

表达式可能包含

  • defined 标识符defined (标识符) 形式的一元运算符。如果 标识符定义为宏名,则结果为 1,否则结果为 0__has_­include __has_cpp_attribute(自 C++20) 在此上下文中被视为已定义的宏的名称。(自 C++17)
  • (自 C++17) __has_include 表达式,它检测头文件或源文件是否存在。
  • (自 C++20) __has_cpp_attribute 表达式,它检测是否支持给定的属性令牌及其支持的版本。

在所有宏展开和 defined__has_include(自 C++17)__has_cpp_attribute(自 C++20) 表达式的求值之后,任何不是 布尔字面量 的标识符都将替换为数字 0 (这包括词法上是关键字但不是像 and 这样的备用记号的标识符)。

然后,表达式被求值为 整型常量表达式

如果 表达式 的求值结果为非零值,则包含受控制的代码块,否则跳过。

注意:在 CWG 问题 1955 解决之前, #if cond1 ... #elif cond2#if cond1 ... #else 后跟 #if cond2 不同,因为如果 cond1 为真,则跳过第二个 #if,并且 cond2 不需要格式良好,而 #elifcond2 必须是有效的表达式。 根据 CWG 1955,导致跳过代码块的 #elif 也被跳过。

[编辑] 组合指令

检查标识符是否被 定义为宏名

#ifdef 标识符 本质上等价于 #if defined 标识符

#ifndef 标识符 本质上等价于 #if !defined 标识符

#elifdef 标识符 本质上等价于 #elif defined 标识符

#elifndef 标识符 本质上等价于 #elif !defined 标识符

(自 C++23)

[编辑] 注解

虽然 #elifdef#elifndef 指令的目标是 C++23,但鼓励实现将它们向后移植到较旧的语言模式作为符合标准的扩展。

[编辑] 示例

#define ABCD 2
#include <iostream>
 
int main()
{
 
#ifdef ABCD
    std::cout << "1: yes\n";
#else
    std::cout << "1: no\n";
#endif
 
#ifndef ABCD
    std::cout << "2: no1\n";
#elif ABCD == 2
    std::cout << "2: yes\n";
#else
    std::cout << "2: no2\n";
#endif
 
#if !defined(DCBA) && (ABCD < 2*4-3)
    std::cout << "3: yes\n";
#endif
 
 
// Note that if a compiler does not support C++23's #elifdef/#elifndef
// directives then the "unexpected" block (see below) will be selected.
#ifdef CPU
    std::cout << "4: no1\n";
#elifdef GPU
    std::cout << "4: no2\n";
#elifndef RAM
    std::cout << "4: yes\n"; // expected block
#else
    std::cout << "4: no!\n"; // unexpectedly selects this block by skipping
                             // unknown directives and "jumping" directly
                             // from "#ifdef CPU" to this "#else" block
#endif
 
// To fix the problem above we may conditionally define the
// macro ELIFDEF_SUPPORTED only if the C++23 directives
// #elifdef/#elifndef are supported.
#if 0
#elifndef UNDEFINED_MACRO
#define ELIFDEF_SUPPORTED
#else
#endif
 
#ifdef ELIFDEF_SUPPORTED
    #ifdef CPU
        std::cout << "4: no1\n";
    #elifdef GPU
        std::cout << "4: no2\n";
    #elifndef RAM
        std::cout << "4: yes\n"; // expected block
    #else
        std::cout << "4: no3\n";
    #endif
#else // when #elifdef unsupported use old verbose `#elif defined`
    #ifdef CPU
        std::cout << "4: no1\n";
    #elif defined GPU
        std::cout << "4: no2\n";
    #elif !defined RAM
        std::cout << "4: yes\n"; // expected block
    #else
        std::cout << "4: no3\n";
    #endif
#endif
}

可能的输出

1: yes
2: yes
3: yes
4: no!
4: yes

[编辑] 缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布行为 正确行为
CWG 1955 C++98 失败的 #elif 的表达式需要有效 失败的 #elif 被跳过

[编辑] 参见

C 文档 关于 条件包含