一般情况下,if 语句的条件表达式在运行时求值。
然而,若条件为常量表达式,如下例所示,则情形有所不同:
#include <iostream>
int main()
{
    constexpr double gravity{ 9.8 };
    // 提示:同一类型的低精度浮点字面量可直接进行相等比较
    if (gravity == 9.8)   // 常量表达式,恒为真
        std::cout << "Gravity is normal.\n";   // 将始终执行
    else
        std::cout << "We are not on Earth.\n"; // 永不执行
    return 0;
}
由于 gravity 被声明为 constexpr 并以值 9.8 初始化,条件 gravity == 9.8 必然为真,于是 else 分支永远不会执行。
在运行时对一个 constexpr 条件求值是一种浪费(其结果始终不变),同样,把永远不会执行的代码也编译进可执行文件也是一种浪费。
C++17 的 constexpr if 语句
C++17 引入了 constexpr if 语句,其条件必须是常量表达式,并在编译时求值。
- 若 constexpr条件为真,则整个if-else结构被替换为 true-statement;
- 若为假,则整个 if-else结构被替换为 false-statement(若存在),否则替换为空。
使用 constexpr if 时,需在 if 后添加关键字 constexpr:
#include <iostream>
int main()
{
    constexpr double gravity{ 9.8 };
    if constexpr (gravity == 9.8)   // 使用 constexpr if
        std::cout << "Gravity is normal.\n";
    else
        std::cout << "We are not on Earth.\n";
    return 0;
}
编译上述代码时,编译器在编译期求值,发现条件恒为真,于是只保留 std::cout << "Gravity is normal.\n"; 这一语句。
换句话说,编译器实际生成的代码等价于:
int main()
{
    constexpr double gravity{ 9.8 };
    std::cout << "Gravity is normal.\n";
    return 0;
}
最佳实践
当条件为常量表达式时,优先使用 constexpr if 而非普通 if。
现代编译器与 C++17 中的 constexpr 条件
出于优化目的,现代编译器通常会把带有 constexpr 条件的普通 if 视为 constexpr if 来处理,但并非强制要求。
若编译器遇到带 constexpr 条件的普通 if,可能会发出警告,提示改用 if constexpr,以确保即使关闭优化也能在编译期完成求值。
