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