constexpr 表示编译期可求值,要求初始化为常量表达式;const 仅保证运行时不可修改,允许运行时初始化。constexpr 隐含 const,但 const 不隐含 constexpr。

constexpr 表示“编译期可求值”,强调表达式能在编译阶段被完全计算出来;const 表示“运行时不可修改”,只承诺对象初始化后值不变,不保证何时确定。
const 只管“不变”,不管“何时定”
const 变量可以依赖运行时信息初始化,比如函数参数、用户输入、系统时间等。只要初始化后不再改,就满足 const 语义。
- int x = 42; const int a = x; // 合法:a 是 const,但值在运行时才确定
- const int b = rand(); // 合法(C++11 起),b 是 const,但值随机且运行时产生
- const int arr[5] = {1,2,3,4,5}; // 数组内容不可改,但数组本身不是编译期常量(不能用作模板非类型参数)
constexpr 要求“编译期可算尽”
constexpr 变量必须用常量表达式初始化;constexpr 函数在传入常量表达式时,必须能产出常量表达式;其本质是向编译器发出“请在编译期算出结果”的请求。
- constexpr int c = 3 + 4; // 合法:纯字面量运算,编译期完成
- constexpr int d = a; // 错误:a 不是常量表达式(即使它值固定,但未标记 constexpr)
- constexpr int fib(int n) { return n
用途差异决定能否互换
有些场景强制要求编译期已知的值,const 不够,必须用 constexpr。
立即学习“C++免费学习笔记(深入)”;
- 数组大小:int arr[constexpr_val]; ✅ / int arr[const_val]; ❌(除非 const_val 是 constexpr)
- 模板非类型参数:std::array
→ N 必须是常量表达式 - case 标签:switch (x) { case constexpr_val: ... } ✅ / case const_val: ❌
- static_assert 条件:static_assert(x > 0); → x 必须是常量表达式
constexpr 不等于“一定在编译期执行”
constexpr 函数具有双重身份:当参数是常量表达式时,它参与编译期计算;否则,它退化为普通函数,在运行时调用。
- constexpr int square(int x) { return x * x; }
- constexpr int s1 = square(5); // 编译期算出 25
- int y = 7; int s2 = square(y); // 运行时调用,和普通函数无异
const 与 constexpr 可以共存,但语义不重叠
constexpr 隐含 const(constexpr 变量一定是只读的),但 const 不隐含 constexpr。显式写 constexpr const 没必要,因为 constexpr 已包含 const 语义。
- constexpr int x = 42; // 等价于 const 且编译期可知
- const int y = 42; // 是 const,但不是常量表达式(除非 42 是字面量且上下文允许提升)
- constexpr const int z = 42; // 合法但冗余,C++ 允许,无实际增益











