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
的赋值将不起作用,因为 S
是 constexpr
变量,并且必须分配编译时 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
。