constexpr/consteval/constinit

(2 mins to read)

constexpr

constexpr用于表达常量表达式,可以作用到变量和函数上,表示该变量在编译期求值的,或者该函数可以在编译期求值(显然需要提供的函数参数都是常量表达式)。

const用于传达只读,constexpr用于传达常量。

1
2
3
constexpr int f(int n) { // 这也是允许的,但显然只有传入的n是常量时才能编译期求值
return n + 1;
}

consteval

consteval是一种局限的constexpr,只能作用到函数上,它强制该函数是完全编译期求值的,不能在运行时调用。

constinit

constinit仅与具有静态存储期(生命期等于整个程序)的变量的初始化有关。

具体有两种情况:

  1. 在编译期静态初始化,即初始值为常量表达式(constant initialization)
  2. 动态初始化,即运行时按执行流遇到的声明顺序计算

第2种方式存在初始化顺序不确定的问题(主要是全局变量)。

考虑两个编译单元中有两个全局变量A和B,而A的初始化依赖于B,但是A和B的初始化顺序是未定义的,一旦A先于B初始化,就会发生段错误。一种解决方式就是改用函数内的静态变量(即单例范式来替代裸的全局变量)。注意局部静态变量是在第一次函数调用时初始化的,因此如果存在依赖关系,要特别注意函数调用的顺序。

constinit作用在具有静态存储期的变量上,强制其在编译期初始化(即第1种方式)。constinit没有const语义,它修饰的变量仍然是可修改的,它与其它const是完全不同的(名字取得有误导性)。

事实上constexpr蕴含了constinit,但是多了const的限制。