前言
const constexpr 还有consteval constinit, 他们到底有什么区别和联系?
提示:以下是本篇文章正文内容,下面案例可供参考
一、const
- const是变量类型名的一部分,即 part of type name,一个名字叫“const T”的类型,和T这个类型本身处于一种平级的关系
- 既然const T只是一个类型,那么以它为类型的变量就既可以在编译期间初始化,也可以在运行期间初始化。
二、constexpr
- constexpr是声明的一部分,即 part of a declaration,他不是变量类型的一部分。
- constexpr的主要作用是声明变量的值或函数的返回值可以在常量表达式(即编译期便可计算出值的表达式)中使用,没有constexpr函数之前,我们无法在需要编译期常量的地方使用函数的返回值。
- 当引用变量用constexpr修饰时,这个引用变量所指向的object必须也在编译期获得明确的初始化,即初始化涉及到的所有运算都必须是可以在编译期间完成的。
- 假如我们想用某个构造函数来给constexpr变量赋值时,这个构造函数就必须用constexpr修饰。
- constexpr修饰函数时对函数的要求:
-
除了函数自己的参数, 函数只能引用全局不变常量 。
-
函数只能调用其他 constexpr 修饰的函数。
-
如果你想要函数调用表达式的返回值能作为编译期常量使用, 首先实参必须是编译时能确定值的常量. 而不管函数是否用到该实参,就算返回值确实是一个字面量
#include <iostream> #include <array> using namespace std; constexpr int foo(int i) { return 5; } int main() { int i = 10; std::array<int, foo(5)> arr; // OK foo(i); // Call is Ok // But... std::array<int, foo(i)> arr1; // Error 除非 i 用constexpr 声明 }
简单的来说,如果其传入的参数是编译期常量,那么这个函数就会产生编译时期的值。但是,传入的参数如果不是编译期常量,那么constexpr修饰的函数就和普通函数一样了。
-
- constexpr函数即可以在编译期间运行,也可以在运行时运行,这样做是为了避免产生同一个函数需要写编译期和运行期两个重复版本的麻烦。
- C++11 标准规定,如果 constexpr 修饰的模板函数实例化结果不满足常量表达式函数的要求,则 constexpr 会被自动忽略
- 在使用constexpr声明一个类型为T的变量时,constexpr会自动把这个变量定义为const T类型。即constexpr在完成它本职工作(告诉编译器这是个编译期常量)的同时,还把原来的T类型改为了const T类型。
三、consteval
- consteval 则可以看作是更加严格的constexpr,它只能用于函数的声明,所有对它的调用都必须在编译期完成,而不能在运行期,因此可以保证在生成的代码中不包含任何对consteval函数的调用。
四、constinit
- constinit 的作用在于显式地指定变量的初始化方式为静态初始化。所有使用constinit声明的变量,其生命周期必须为静态生命周期或线程本地(Thread-local)生命周期(即不能为局部变量),其初始化表达式必须是一个常量表达式。
————————————————
摘录自
总结
时代在进步,特性在增加, 名字会有遗留问题