一、一句话总览
const:运行期只读
constexpr:编译期常量 + 运行期也可用
关键字 核心语义
const 承诺"我不会修改它"
constexpr 承诺"它在编译期就能算出来"
二、核心区别详解
1️⃣ 求值时机不同(最关键)
✅ const
int x = 10;
const int a = x; // ✅ 合法
• a 的值在运行期确定
• 只要初始化完成,之后不能再改
👉 不要求是编译期常量
✅ constexpr
constexpr int a = 10; // ✅
constexpr int b = x; // ❌ x 不是编译期常量
• 必须在编译期可求值
• 编译器会在编译阶段计算
✅ 可用作:
• 数组大小
• 模板参数
• switch case
• 位宽等
constexpr int N = 10;
int arrN; // ✅
2️⃣ 对函数和表达式的支持
✅ constexpr 函数
constexpr int square(int x) {
return x * x;
}
constexpr int y = square(5); // 编译期计算
• 若参数是编译期常量 → 编译期求值
• 否则 → 运行期函数
int x = 3;
int z = square(x); // 运行期调用
📌 constexpr ≠ 只能编译期执行
❌ const 不能修饰函数返回值表示"常量表达式"
const int f(); // 只是返回值不可修改
3️⃣ 修饰指针时的差异
const
const int* p; // 指向的内容不可改
constexpr
constexpr int x = 10;
constexpr const int* p = &x; // ✅
📌 constexpr 指针:
• 指针本身是常量
• 指向的对象也必须是编译期常量
4️⃣ 与 static_assert / 模板参数的关系
constexpr int N = 5;
static_assert(N == 5, "error");
template
struct A {};
A a; // ✅
❌ const 做不到
三、C++11 之后的演进
C++11
• constexpr 函数只能有一个 return
• 只能用于字面量类型
C++14
• 允许局部变量
• 允许循环、条件语句
constexpr int sum(int n) {
int s = 0;
for (int i = 1; i <= n; ++i)
s += i;
return s;
}
C++20
• 放宽更多限制
• 允许虚函数、try-catch
四、典型对比示例
场景 const constexpr
数组大小 ❌ ✅
switch case ❌ ✅
模板参数 ❌ ✅
运行期变量 ✅ ✅
防止误修改 ✅ ✅
五、什么时候用哪个?
✅ 用 const
• 只想防止误修改
• 值在运行期才确定
• 函数参数、成员函数
void foo(const std::string& s);
✅ 用 constexpr
• 需要编译期常量
• 性能敏感(零运行时开销)
• 泛型 / 模板 / 元编程
constexpr double PI = 3.1415926;
六、一句话总结(面试版)
const 强调"不可修改",constexpr 强调"能在编译期算出来"。
所有 constexpr 都是 const,但不是所有 const 都是 constexpr。