Skip to content

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 的使用放宽了许多约定,暂时没用到就不详细讲解。