一、从 C++11 引入
1. 常量表达式和 constexpr 关键字的概念
现代 C++ 从 C++11 开始引入了常量表达式和 constexpr 关键字,并在后续标准中不断更新。
常量表达式是指值不会改变并且在编译过程中就能得到计算结果的表达式。用字面量或常量表达式初始化的 const 对象都是常量表达式。但用变量初始化的 const 对象则不是。
const int a = 1; // a 是常量表达式
const int b = a + 1; // b 是常量表达式
int c = 1; // c 不是常量表达式
const int d = c; // d 不是常量表达式,因为可能有代码影响 c 的值,编译时期无法确定 c 的值
由于常量表达式的值在编译时期就能确定,编译器可以直接进行优化,在使用常量表达式的地方直接替换为值。通过汇编语言通常能看出区别。
常量表达式的最大优点就是能将一些计算从运行时转移到编译时,提升程序运行时的性能。
C++11 引入了 constexpr 关键字,用于指定常量表达式,允许在编译时计算表达式的值。constexpr 可以修饰变量,但修饰的变量必须是常量表达式,且必须用常量或常量表达式进行初始化,否则会报错。
constexpr 也可以修饰指针,但修饰的是指针本身(即顶层 const)。
const 可以分为顶层 const、底层 const。本身被 const 修饰叫做顶层 const,指向的对象被 const 修饰叫做底层 const。大多数普通对象被 const 修饰时都是顶层 const;指针被 const 修饰时,
*左边的 const 叫做底层 const,*右边的 const 叫做顶层 const;const 修饰引用时,是底层 const。
2. constexpr 修饰函数
constexpr 可以修饰函数,constexpr 函数默认都是 inline 的,函数的计算会由编译器在编译时期执行。但是,一个函数的逻辑比表达式复杂得多,这对编译器的要求更加严格。因此在 C++11 标准中,对 constexpr 修饰的函数要求十分严格:
- 这个函数的参数和返回值必须都是字面类型(目前可以理解为包括整型、浮点型、指针、引用等)
- 函数体中只能包含一条语句且是 return 语句
- 函数体中不能定义局部变量,不能有循环语句、条件语句
- 函数必须有返回值,返回值必须是常量表达式。函数如果有参数,必须传常量或常量表达式(不这样传参,要用普通变量接收函数结果,此时这个函数还是普通函数的运行执行)
constexpr 函数的返回结果,必须用一个常量表达式进行接收,才能触发编译器的优化。否则这个函数还是像普通函数一样,在运行调用时才会计算:
constexpr int func1() { return 1; }
constexpr { x + ; }
{ n <= ? : n * (n - ); }
{
a = ();
b = ();
c = ();
cout << a << endl;
cout << b << endl;
cout << c << endl;
;
}


