constexpr 编译器常量表达式
引入
原先表达常量表达式有 const 关键字,但是 cosnt 关键字既能够表示编译期的常量也能够保证运行时候的常量:
cpp
int i = 100;
//编译期常量,值在编译的时候就知道
const int a = 200;
//运行时常量,常量的值在运行的时候才能知道
const int b = i;
在一些绝对需要编译期常量的场合,使用运行时候的常量会导致错误,最典型的场合比如书上举例的:
cpp
const int a = 100;
const int b = i;
int c[a]; //编译通过
int d[b]; //编译错误
就是因为 b 是一个运行时候的常量导致了这种错误。为了避免这种错误,cpp 在 c++11 中引入了 constexpr
用这个关键字来代表编译期的常量,表示常量表达式的结果绝对是在编译器计算出来。
constexpr
感觉就是对常量的类型再做了一次区分,如果给编译期的常量一个运行时候的值,马上会报错:
cpp
int a = 100;
constexpr b = a; //error
由于 a 是一个运行时候的值,因此直接报错。
constexpr 函数
constexpr 能够作用于函数上,表示函数的返回值能够被在编译期计算,注意这里是能够:
cpp
constexpr int get(int x){
return x + 1;
}
int b[get(100)];
以上的代码是能够编译通过的,因为函数是 constexpr 的,在接收到 100 这个常量的参数之后,其在编译期就计算出了这个函数的返回值是 101,然后成功的将数组初始化。
上面的函数定义表示接收的函数参数为 int x,但是如果传入的不是一个运行时候的常量怎么办:
cpp
int c = 100;
int b[get(c)]; //error
上面这个函数会果断报错,对于 constexpr 函数,如果传入的值是编译期的值,那结果确实会在编译器被算出来,但是如果传入的是一个运行时候的值,函数仍然能够正确执行,但是其退化成了一个普通的函数,相当于:
cpp
int get(int x){
return x + 1;
}
这就是 constexpr 函数的函数退化。
其他
constexpr 还能用于构造函数、静态变量初始化等等,同时后续的标准也对 constexpr 的使用放宽了许多约定,暂时没用到就不详细讲解。