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
。