constexpr 功能

声明为 constexpr 的函数是隐式内联的,并且对此类函数的调用可能会产生常量表达式。例如,如果使用常量表达式参数调用,则以下函数也会生成一个常量表达式:

Version >= C++ 11

constexpr int Sum(int a, int b)
{
    return a + b;
}

因此,函数调用的结果可以用作数组绑定或模板参数,或初始化 constexpr 变量:

Version >= C++ 11

int main()
{
    constexpr int S = Sum(10,20);
   
    int Array[S];
    int Array2[Sum(20,30)]; // 50 array size, compile time
}

请注意,如果从函数的返回类型规范中删除 constexpr,则对 S 的赋值将不起作用,因为 Sconstexpr 变量,并且必须分配编译时 const。同样,如果函数 Sum 不是 constexpr,则数组的大小也不会是常量表达式。

有关 constexpr 函数的有趣之处在于你也可以像普通函数一样使用它:

Version >= C++ 11

int a = 20;
auto sum = Sum(a, abs(-20));

Sum 现在不是 constexpr 函数,它将被编译为普通函数,接受变量(非常量)参数,并返回非常量值。你不需要写两个函数。

它还意味着如果你尝试将此类调用分配给非 const 变量,则它将无法编译:

Version >= C++ 11

int a = 20;
constexpr auto sum = Sum(a, abs(-20));

原因很简单:constexpr 只能分配一个编译时常量。但是,上面的函数调用使得 Sum 成为非 constexpr(R 值是非常数,但 L 值表示自己是 constexpr)。

constexpr 函数还必须返回编译时常量。以下将无法编译:

Version >= C++ 11

constexpr int Sum(int a, int b)
{
    int a1 = a;     // ERROR
    return a + b;
}

因为 a1 是一个非 constexpr 变量,并且禁止该函数成为真正的 constexpr 函数。将它设为 constexpr 并将其分配为 a 也不起作用 - 因为 a(传入参数)的值仍然未知:

Version >= C++ 11

constexpr int Sum(int a, int b)
{
   constexpr int a1 = a;     // ERROR
   ..

此外,以下也将无法编译:

Version >= C++ 11

constexpr int Sum(int a, int b)
{
   return abs(a) + b; // or abs(a) + abs(b)
}

由于 abs(a) 不是一个恒定的表达(即使 abs(10) 不起作用,因为 abs 没有返回 constexpr int

那这个呢?

Version >= C++ 11

constexpr int Abs(int v)
{
    return v >= 0 ? v : -v;
}

constexpr int Sum(int a, int b)
{
    return Abs(a) + b;
}

我们制作了自己的 Abs 功能,这是一个 constexpr,而 Abs 的身体也没有打破任何规则。此外,在呼叫站点(Sum 内),表达式评估为 constexpr。因此,对 Sum(-10, 20) 的调用将是一个编译时常量表达式,导致 30