简介

constexpr在 C++11 引入、在 C++14 得到大幅改进。

(1)C++11中的constexpr指定的函数返回值和参数必须要保证是字面值,而且必须只有一行return代码,这给函数的设计者带来了更多的限制,比如通常只能通过return 三目运算符+递归来计算返回的字面值。

(2)C++14中只要保证返回值和参数是字面值就行了,函数体中可以加入更多的语句,方便了更灵活的计算。

它的字面意思是 constant expression,常量表达式。

其实,const并不能代表“常量”,它仅仅是对变量的一个修饰,告诉编译器这个变量只能被初始化,且不能被直接修改(实际上可以修改)。而这个变量的值,可以在运行时也可以在编译时指定。

const变量通过指针修改的例子:

常变量的值在赋值后不能被改变并不是真的不能改变,而是对于高级语言语法上的限制,实际上常变量在运行时并不是存放在只读内存区,因此只要在程序运行时获取到变量的地址,即可对其进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//实验1:
#include <iostream>
using namespace std;

void showValue(const int &val)
{
cout << val << endl;
}

int main()
{
const int val = 10;
int *ptr;
void *p = (void *)&val;

ptr = (int *)p;
(*ptr)++;

cout << &val << endl;
cout << val << endl;
showValue(val);
return 0;
}

结果:
0x7ffe90e42cdc
10
11
//可以看到11是正确的,但是前面这个10应该是编译器优化了的原因,此时我如果在main里面继续使用val,结果可能会有问题,因此不建议修改const变量

//实验2:
//加上volatile关键字的结果呢
void showValue(const volatile int &val)
{
cout << val << endl;
}

int main()
{
const volatile int val = 10;
int *ptr;
void *p = (void *)&val;

ptr = (int *)p;
(*ptr)++;

cout << &val << endl;
cout << val << endl;
showValue(val);
return 0;
}
结果:
1
11
11
constexpr

constexpr可以用来修饰变量、函数、构造函数。一旦以上任何元素被constexpr修饰,那么等于说是告诉编译器 “请大胆地将我看成编译时就能得出常量值的表达式去优化我”。
如:

1
2
3
4
5
6
7
const int func() {
return 10;
}
main(){
int arr[func()];
}
//error : 函数调用在常量表达式中必须具有常量值

对于func() ,胆小的编译器并没有足够的胆量去做编译期优化,哪怕函数体就一句return 字面值;

1
2
3
4
5
6
7
constexpr func() {
return 10;
}
main(){
int arr[func()];
}
//编译通过

则编译通过
编译期大胆地将func()做了优化,在编译期就确定了func计算出的值10而无需等到运行时再去计算。

这就是constexpr的第一个作用:给编译器足够的信心在编译期去做被constexpr修饰的表达式的优化。

constexpr还有另外一个特性,虽然它本身的作用之一就是希望程序员能给编译器做优化的信心,但它却猜到了自己可能会被程序员欺骗,而编译器并不会对此“恼羞成怒”中止编译,如:

1
2
3
4
5
6
7
8
constexpr int func(const int n){
return 10+n;
}
main(){
const int i = cin.get();
cout<<func(i);
}
//编译通过

程序员告诉编译器尽管信心十足地把func当做是编译期就能计算出值的程式,但却欺骗了它,程序员最终并没有传递一个常量字面值到该函数。没有被编译器中止编译并报错的原因在于编译器并没有100%相信程序员,当其检测到func的参数是一个常量字面值的时候,编译器才会去对其做优化,否则,依然会将计算任务留给运行时。

参考链接:

https://www.jianshu.com/p/34a2a79ea947

https://mp.weixin.qq.com/s/206vQMt5wryvB_blesMcRA