07 April 2022

C++ 核心指南目录

F.4: If a function might have to be evaluated at compile time, declare it constexpr

理由

通过 constexpr 让编译器在编译期进行计算。

例子

著名(臭名昭著?)的阶乘计算:

constexpr int fac(int n)
{
    // constexpr enables max_exp to be used in Expects
    constexpr int max_exp = 17;
    // prevent silliness and overflow
    Expects(0 <= n && n < max_exp);
    int x = 1;
    for (int i = 2; i <= n; ++i)
        x *= i;
    return x;
}
int main()
{
    cout << fac(10);
    return 0;
}
3628800

C++14 可以这么玩。C++11 可以用递归方式计算。

注意

constexpr 不保证编译时能计算出来。它只是保证,在程序员要求的时候,或在编译器进行优化的时候,常量表达式参数可以在编译时计算。

constexpr int min(int x, int y) { return x < y ? x : y; }

void test(int v)
{
    int m1 = min(-1, 2);            // probably compile-time evaluation
    constexpr int m2 = min(-1, 2);  // compile-time evaluation
    int m3 = min(-1, v);            // run-time evaluation
    constexpr int m4 = min(-1, v);  // error: cannot evaluate at compile time
}
int main()
{
    test(10);
    return 0;
}

编译出错:

'v' is not a constant expression
 17 |     constexpr int m4 = min(-1, v);
    |                                 ^

注意

不要把所有函数的声明为 constexpr 。很多计算适合在运行时进行。

注意

如果是需要在更高一层级运行时进行配置计算或业务逻辑运算的 API,不能是 constexpr 的。因为编译器无法优化。任何依靠这些 API 的 constexpr 函数最终都要重构,或去掉 constexpr

强化

编译器调用到声明为 constexpr 的函数时,如果函数中使用了可变变量,就会报错。