Constexpr

constexpr是C++11引入的关键字，用于编译时的常量与常量函数。

声明为constexpr函数的意义是：如果其参数均为合适的编译期常量，则对这个constexpr函数的调用就可用于期望常量表达式的场合（如模板的非类型参数，或枚举（enum）常量的值）。如果参数的值在运行期才能确定，或者虽然参数的值是编译期常量，但不-{zh-cn:匹配;zh-tw:符合;}-这个函数的要求，则对这个函数调用的求值只能在运行期进行。

简介
C++编译时可确定常量表达式的结果，因此可在编译时优化。C++规范在一些地方要求使用常量表达式，如声明数组的-{zh-hans:维数;zh-hant:維度;}-。但常量表达式不允许包含函数调用或者对象构造。因此下述代码无效：

int get_five() {return 5;}

int some_value[get_five() + 7]; // 创建包含12个整数的数组. C++03中非法，因为get_five() + 7不是常量表达式 

C++11引入了关键字constexpr，允许编程者保证函数或对象的构造函数是编译时常量。上述代码可以改写为：

constexpr int get_five() {return 5;}

int some_value[get_five() + 7]; // Create an array of 12 integers. Valid C++11

constexpr函数必须满足下述限制：
 函数-{zh-hans:返回;zh-hant:回傳;}-值不能是void-{zh-cn:类型;zh-tw:型別;}-
 函数体不能声明变量或定义新的-{zh-cn:类型;zh-tw:型別;}-
 函数体只能包含声明、null语句或者一段return语句
 在形参实参结合后，return语句中的表达式为常量表达式

C++11去掉了const variable必须是-{zh-cn:整型;zh-tw:整數型別}-（Integral Type）或者枚举型別的限制，只要是用于关键字constexpr定义即可：
constexpr double earth_gravitational_acceleration = 9.8;
constexpr double moon_gravitational_acceleration = earth_gravitational_acceleration / 6.0;
这些variable必须用常量表达式初始化。

为-{zh-cn:构造;zh-tw:建構;}-用户定义类型的常量表达式，构造函数必须用constexpr声明，函数体仅包含声明或null语句，不能声明变量或定义-{zh-hans:类型;zh-tw:資料型別}-。因此，构造函数的实参值应该是常量表达式，直接初始化-{zh-hans:类;zh-hant:類別;}-的-{zh-hans:数据;zh-hant:資料;}-成员。析构函数是平凡的。类型的-{zh-hans:拷贝;zh-tw:複製;}-构造函数应该也定义为constexpr，以允许constexpr函数返回一个该类型的对象。类型的成员函数都应该是constexpr。

constexpr函数或构造函数的实参值如果不是常量表达式，那么调用行为与结果就不是常量表达式。

C++14-{zh-cn:放松;zh-hant:放寬;}-了这些限制。声明为constexpr的函数可以含有以下内容：
 任何声明，除了：
 static或thread_local变量。
 没有初始化的变量声明。
 条件分支语句if和switch。
 所有的迴圈语句，包括基于范围的for迴圈。
 表达式可以改变一个对象的值，只需该对象的-{zh-cn:生命期;zh-tw:生命週期;}-在声明为constexpr的函数内部开始。包括对有constexpr声明的任何非const非静态成员函数的调用。

goto仍然不允许在constexpr函数中出现。

constexpr-{zh-hans:支持;zh-hant:支援;}-编译期的递归。例如，可以写一个constexpr函数计算斐波那契数列。

此外，C++11指出，所有被声明为constexpr的非静态成员函数也隐含声明为const（即函数不能修改*this的值）。C++14已经删除此点，非静态成员函数可以为非const。

示例代码
// C++98/03
template <int N>
struct Factorial_Cpp03
{
    const static int value = N * Factorial_Cpp03<N - 1>::value;
};
template <>
struct Factorial_Cpp03<0>
{
    const static int value = 1;
};

// C++11
constexpr int factorial_Cpp11(int n)
{
    return n == 0 ? 1 : n * factorial_Cpp11(n - 1);
}

// C++14
constexpr int factorial_Cpp14(int n)
{
    int result = 1;
    for (int i = 1; i <= n; ++i)
        result *= i;
    return result;
}

int main()
{
    static_assert(Factorial_Cpp03<3>::value == 6, "error");
    static_assert(factorial_Cpp11(3) == 6, "error");
    static_assert(factorial_Cpp14(3) == 6, "error");
    return 0;
}

参考文献

Category:C++
Category:计算机编程