constexpr
和 const
是 C++ 中用于定义常量的关键字,但它们在语义、应用场景和编译期行为上有显著差异。以下是两者的核心区别:
1. 核心语义差异
-
const
- 只读性:表示变量或对象的值在初始化后不可修改,但值的确定可以发生在 编译期或运行期。
- 适用性:可修饰变量、指针、引用、成员函数等。例如:
const int x = 5; // 编译期确定 const int y = getValue(); // 运行时确定(若 getValue() 非编译期可计算)
- 指针与引用:
const int* p
:指针指向的值不可变(底层const
)。int* const p
:指针本身不可变(顶层const
)1240。
-
constexpr
- 编译期确定性:要求变量或函数的结果必须在 编译期可计算,且必须是字面值类型(如整数、浮点数、字符串字面量等)。
- 适用性:修饰变量、函数、构造函数等。例如:
constexpr int square(int x) { return x * x; } constexpr int result = square(5); // 编译时计算为 25
- 隐式
const
:constexpr
修饰的变量默认是const
的,但const
变量不一定是constexpr
11440。
2. 应用场景差异
-
const
的典型用途:- 声明运行时不可修改的变量或参数(如函数参数保护)。
- 修饰类成员函数为
const
,表示不修改对象状态。 - 定义指针或引用指向不可变对象240136。
-
constexpr
的典型用途:- 编译期计算:如数组大小、模板参数、静态断言等需要编译期常量的场景。
- 优化性能:将计算提前到编译期,减少运行时开销。例如:
constexpr int factorial(int n) { return (n <= 1) ? 1 : n * factorial(n-1); } int arr[factorial(5)]; // 数组大小在编译时确定
- 与模板元编程结合,生成编译期数据结构144392。
3. 函数修饰的差异
-
const
成员函数:- 保证函数不修改类的非静态成员变量。
- 常量对象只能调用
const
成员函数。 - 示例:
class MyClass { public:int getValue() const { return value; } // 不修改成员 private:int value; };
-
constexpr
函数:- 函数体必须简单(C++11 限制较严,C++14 后允许循环、局部变量等)。
- 参数和返回值必须是字面值类型。
- 示例:
constexpr int add(int a, int b) { return a + b; } constexpr int sum = add(3, 4); // 编译时计算
- 若参数是编译期常量,则函数在编译时求值;否则退化为普通函数4392136。
4. 指针与引用的处理
-
constexpr
指针:- 必须指向编译期可确定的地址(如全局变量或静态变量)。
- 示例:
static int global = 10; constexpr int* p = &global; // 合法
-
const
指针:- 可以指向运行时确定的地址。
- 示例:
int x = 5; const int* p = &x; // 合法(底层 const)
5. 版本演进与兼容性
-
C++11 与 C++14 的区别:
- C++11:
constexpr
函数限制严格(如只能有一条return
语句)。 - C++14 及更高版本:放宽限制,允许局部变量、循环等复杂逻辑43124。
- C++11:
-
成员函数的隐式
const
:- 在 C++11 中,
constexpr
成员函数隐式包含const
修饰;C++14 后需显式声明const
以避免歧义1140154。
- 在 C++11 中,
总结对比表
特性 | const | constexpr |
---|---|---|
确定时机 | 编译期或运行期 | 必须编译期确定 |
变量初始化 | 可用运行时表达式 | 必须用编译期常量表达式 |
函数返回值 | 无特殊要求 | 必须为编译期可计算的常量表达式 |
指针修饰 | 可修饰指向内容或指针本身 | 仅修饰指针本身(必须编译期地址) |
类成员函数 | 表示不修改对象状态 | 允许编译期计算,C++14 后需显式 const |
优化潜力 | 无编译期计算优化 | 编译期计算提升性能 |
何时选择?
- 优先
constexpr
:需要编译期计算(如数组大小、模板参数)或优化性能时。 - 使用
const
:仅需运行时不可修改的变量或保护函数参数时21440。