關鍵字 constexpr
於 C++11 中引入並於 C++14 中得到改善。它表示常數表達式。與 const
相同,它可應用於變量,因此如果任何代碼試圖修改該值,均將引發編譯器錯誤。與 const
不同,constexpr
也可應用於函數和類構造函數。 constexpr
指示值或返回值是常數,並且如果可能,將在編譯時計算值或返回值。
constexpr
變量const
和 constexpr
變量之間的主要區別在於:const
變量的初始化可以延遲到運行時,而 constexpr
變量必須在編譯時進行初始化。所有 constexpr
變量均為常量,因此必須使用常量表達式初始化。
constexpr float x = 42.0;
constexpr float y{108};
constexpr float z = exp(5, 3);
constexpr int i; // Error! Not initialized
int j = 0;
constexpr int k = j + 1; //Error! j not a constant expression
一般來說,如果你認定變量是一個常量表達式,那就把它聲明成為
constexpr
類型。
constexpr
函數constexpr
函數是在使用需要它的代碼時,可以在編譯時計算其返回值的函數。當其參數為 constexpr
值並且在編譯時使用代碼需要返回值時(例如,初始化一個 constexpr
變量或提供一個非類型模板參數),它會生成編譯時常量。使用非constexpr
參數調用時,或編譯時不需要其值時,它將與正則函數一樣,在運行時生成一個值。
#include
using namespace std;
// Pass by value
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
};
// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp2(x * x, n / 2) :
exp2(x * x, (n - 1) / 2) * x;
};
// Compile time computation of array length
template
constexpr int length(const T(&ary)[N])
{
return N;
}
// Recursive constexpr function
constexpr int fac(int n)
{
return n == 1 ? 1 : n*fac(n - 1);
}
// User-defined type
class Foo
{
public:
constexpr explicit Foo(int i) : _i(i) {}
constexpr int GetValue()
{
return _i;
}
private:
int _i;
};
int main()
{
// foo is const:
constexpr Foo foo(5);
// foo = Foo(6); // Error!
//Compile time:
constexpr float x = exp(5, 3);
// const float a = 2.0;
// const int b = 2;
// constexpr float xx = exp2(a, b); // Error!
constexpr float xx = exp2(2.0, 2);
constexpr float y{ exp(2, 5) };
constexpr int val = foo.GetValue();
constexpr int f5 = fac(5);
const int nums[]{ 1, 2, 3, 4 };
const int nums2[length(nums) * 2]{ 1, 2, 3, 4, 5, 6, 7, 8 };
cout << "The value of foo is " << foo.GetValue() << endl;
}
還記得const
與指針的規則嗎?如果關鍵字const
出現在星號左邊,表示被指物是常量;如果出現在星號右邊,表示指針本身是常量;如果出現在星號兩邊,表示被指物和指針兩者都是常量。
與const
不同,在constexpr
聲明中如果定義了一個指針,限定符constexpr
僅對指針有效,與指針所指對象無關。
const int *p = 0; // non-const pointer, const data
constexpr int *q = 0; // const pointer, non-const data
與其它常量指針類似,const
指針既可以指向常量也可以指向一個非常量:
int j = 0;
constexpr int i = 2;
constexpr const int *p = &i; // const pointer, const data
constexpr int *p1 = &j; // const pointer, non-const data