1. 概念
c++11引入的关键字,用于编译时获取常量或常量函数的结果。
constexpr修饰普通变量时,变量必须经过初始化且初始值必须是一个常量表达式。
2. 使用与限制
c++11之前的常量表达式不允许包含函数调用或对象构造,如下所示:
int rValue() {
return 1;
}
int m_iValue[rValue() + 2]; //c++03中error
c++11引入关键字constexpr,允许编程者保证函数或对象的构造函数是编译时常量,代码改写如下:
constexpr int rValue() {
return 1;
}
int m_iValue[rValue() + 2]; //c++11 ok
限制总结如下:
- 函数的返回值不能时void类型;
- 函数体不能声明变量或定义新类型;
- 函数体只能包含声明、null语句或者一条return语句;
- 在形参实参结合后,return语句中的表达式为常量表达式;
为构造用户定义类型的常量表达式,构造函数必须用constexpr声明,函数体仅包含声明或null语句,不能声明变量或定义类型。因此,构造函数的实参值应该是常量表达式,直接初始化类的数据成员。析构函数是平凡的。类型的拷贝构造函数应该也定义为constexpr,以允许constexpr函数返回一个该类型的对象。类型的成员函数都应该是constexpr。
constexpr函数或构造函数的实参值如果不是常量表达式,那么调用行为与结果就不是常量表达式。
3. c++14优化
c++14放松了限制。声明为constexpr的函数可以含有以下内容:
- 任何声明,除了:
-
或static
变量。thread_local
- 没有初始化的变量声明。
-
- 条件分支语句
和if
。switch
- 所有的循环语句,包括基于范围的
循环。for
- 表达式可以改变一个对象的值,只需该对象的生命期在声明为constexpr的函数内部开始。包括对有
声明的任何非constexpr
非静态成员函数的调用。const
goto仍然不允许在constexpr函数中出现。
constexpr支持编译期的递归。例如,可以写一个constexpr函数计算斐波那契数列。
此外,C++11指出,所有被声明为constexpr的非静态成员函数也隐含声明为const(即函数不能修改*this的值)。C++14已经删除此点,非静态成员函数可以为非const
4. 示例
// 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;
}
部分参考:https://zh.wikipedia.org/wiki/Constexpr