constexpr
当它应用与对象时,其实就是一个加强版const
;但是应用于函数时,却有着相当不同的意义;
constexpr
对象:
constexpr
对象具备const
属性,在编译阶段已知
int sz; // 非constexpr变量
constexpr auto arryaSize1 = sz; // 错误!sz的数值在编译器未知
std::array<int, sz> data1; // 错误!sz的数值在编译器未知
constexpr auto arraySize2 = 10; // 没问题,10为编译器常量
std::array<int, arraySize2> data2; // 没问题,arraySize2是个constexpr
注意:const
并未提供和consexpr
同样的保证,因为const
对象不一定经由编译器已知值来初始化;
int sz; // 非constexpr变量
const auto arryaSize1 = sz; // 没问题!arraySize是sz的一个const副本
std::array<int, arryaSize1> data1; // 错误!arryaSize1的数值在编译器未知
一言以蔽之,所有constexpr
对象都是const
对象,但是所有的const
对象并非都是constexpr
对象。如果你想让编译器提供保证,让变量拥有一个值,用于要求编译器期常量的语境,那么能达到这个目的的工具是constexpr
,而非const
constexpr
函数
constexpr
函数可以用在要求编译器常量的语境当中。若你传给一个constexpr
函数的实参数值是在编译期已知,则结果也会在编译期间计算出来- 在调用
constexpr
函数时,若传入的数值有一个或者多个在编译器未知,则它的运作方式和普通函数无差异
考虑一个pow
函数
constexpr int pow(int base, int exp) noexcept { // pow是一个constexpr函数,且不会抛出异常
// ....
}
constexpr auto numConds = 5;
std::array<int, pow(3, numConds)> results; // results有3^numConds个元素
pow
前面写的那个constexpr
并不表明pow
要返回一个const
数值,它表明的是如果base和expr是编译器常量,pow
的反馈结果就可以当一个编译器常量使用。如果base
和expr
中有一个不是编译器常量,则pow
的返回结果就将在执行期计算。
在C++11
中,constexpr
函数不得包含多于一个可执行语句,即一个return
语句。我们可以用条件运算符和递归解决这个问题
// C++11
constexpr int pow(int base, int exp) noexcept {
return (exp == 0 ? 1 : base * pow(base, exp - 1));
}
C++14
限制条件放宽了,下列代码在C++11
中编译不过
constexpr int pow(int base, int exp) noexcept {
int result = 1;
for (int i = 0; i < exp; i++) {
result *= base;
}
return result;
}
// 后面没太看明白用处