参考
正文
constexpr是C++11引入的关键字,用于编译时的常量与常量函数。
声明为constexpr函数的意义是:如果其参数均为合适的编译期常量,则对这个constexpr函数的调用就可用于期望常量表达式的场合(如模板的非类型参数,或枚举常量的值)。如果参数的值在运行期才能确定,或者虽然参数的值是编译期常量,但不匹配这个函数的要求,则对这个函数调用的求值只能在运行期进行。
C++编译时可确定常量表达式的结果,因此可在编译时优化。C++规范在一些地方要求使用常量表达式,如声明数组的维数。但常量表达式不允许包含函数调用或者对象构造。因此下述代码无效:
1 | // error: array bound is not an integer constant before ‘]’ token |
1 | //ok |
constexpr的对象,必须是常量类型的,const则没要求(拷贝副本)。
1 | int main() |
c++11 constexpr函数必须满足下述限制:
- 函数返回值不能是void类型
- 函数体不能声明变量或定义新的类型
- 函数体只能包含声明、null语句或者一条return语句
- 在形参实参结合后,return语句中的表达式为常量表达式
C++14放松了这些限制。声明为constexpr的函数可以含有以下内容:[2]
任何声明,除了:
- static或thread_local变量。
- 没有初始化的变量声明。
- 条件分支语句if和switch。
- 所有的循环语句,包括基于范围的for循环。
- 表达式可以改变一个对象的值,只需该对象的生命期在声明为constexpr的函数内部开始。包括对有constexpr声明的任何非const非静态成员函数的调用。
- goto仍然不允许在constexpr函数中出现。
constexpr支持编译期的递归。例如,可以写一个constexpr函数计算斐波那契数列。
*此外,C++11指出,所有被声明为constexpr的非静态成员函数也隐含声明为const(即函数不能修改this的值)(函数尾部的const,只读函数)。C++14已经删除此点,非静态成员函数可以为非const。**
1 | class cc |
总结
- constexpr函数可以用在要求编译期常量的语境中。在这样的语境中,若你传给一个constexpr函数的实参值是在编译期已知的,则结果也会在编译期间计算出来。如果不能再编译期间计算得到,则编译不能通过
- 在调用constexpr函数时,若传入的值有一个或多个在编译期未知,则它的运作方式和普通函数无异,亦即它也是在运行期执行结果的计算。这意味着,如果函数执行的是同样的操作,仅仅应用的语境一个是要求在编译期常量的,一个是用于所有其他值的话,那就不用写两个函数。