一、C++11 引入 constexpr
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 的值可能在编译前被修改
由于常量表达式的值在编译期确定,编译器可直接替换数值进行优化。通过汇编对比可见,使用常量表达式的地方直接进行了值替换,而非运行时计算。
核心优势在于将部分计算从运行时转移至编译时,从而提升程序运行性能。
constexpr 关键字用于指定常量表达式,允许在编译时计算表达式的值。修饰变量时,该变量必须是常量表达式,且必须用常量或常量表达式初始化。
关于 const 修饰符,需注意顶层 const 与底层 const 的区别:
- 对象本身被
const修饰为顶层 const。 - 指向的对象被
const修饰为底层 const。 - 指针被
const修饰时,*左侧为底层 const,右侧为顶层 const。 const修饰引用时,视为底层 const。
2. constexpr 修饰函数
constexpr 可修饰函数,默认内联(inline),由编译器在编译期执行计算。但由于函数逻辑比表达式复杂,C++11 对 constexpr 函数的限制非常严格:
- 参数和返回值必须是字面类型(整型、浮点型、指针、引用等)。
- 函数体只能包含一条语句,即
return语句。 - 不能定义局部变量,不能有循环或条件语句。
- 必须有返回值,且返回值为常量表达式。
注意:只有当 constexpr 函数的结果被常量表达式接收时,才会触发编译期优化;否则它仍作为普通函数在运行时调用。
此外,constexpr 还可修饰以下场景:
- 构造函数:若类对象需定义为
constexpr,其构造函数必须被constexpr修饰。要求所有成员变量为字面类型,必须在初始化列表中用常量表达式初始化,且函数体为空。析构函数不能做实际清理工作。 - 成员函数:自动成为
const成员函数,参数列表后需加const,函数内不可修改成员变量。不能是虚函数。 - 函数模板:若实例化结果不符合普通 函数要求,则退化为普通函数。


