constexpr 是 C++ 中要求在编译期求值的关键字,用于变量、函数或对象;它强制参与常量表达式计算,否则编译失败,而 const 仅保证运行时不可修改。

constexpr 是 C++ 中用于声明「在编译期就能求值」的变量、函数或对象的关键词。它不是简单的“只读标记”,而是向编译器发出明确指令:这个东西必须能参与常量表达式计算——否则就是编译错误。
什么时候必须用 constexpr 而不能用 const
const 只表示运行时不可修改,constexpr 则要求值在编译期确定。以下场景会直接报错(如 GCC/Clang 提示 error: constexpr variable 'x' must be initialized by a constant expression):
- 作为数组长度:
int arr[constexpr_size];—— 若constexpr_size只是const int但初始化依赖运行时值(如cin >> x; const int n = x;),就不合法 - 非类型模板参数:
std::array要求a; N是constexpr整型 -
case标签值:switch (v) { case kValue: ... }中kValue必须是constexpr - 静态断言:
static_assert(condition, "...");的condition必须是constexpr布尔表达式
constexpr 函数的限制与放宽(C++11 → C++20)
早期 C++11 对 constexpr 函数极其严格:只能包含一个 return 语句,不能有循环、局部变量、分支(if)、异常等。C++14 开始大幅放宽,C++20 允许更多运行时特征(但仍需满足“所有调用路径都能在编译期求值”):
- C++14 起支持多条语句、
if/switch、局部变量、for/while循环(只要循环次数可静态推导) - 函数体仍不能含
new/delete、try/catch、asm等无法在编译期执行的操作 - 若函数被用于需要常量表达式的上下文(如模板参数),则本次调用必须能被编译器静态求值;否则即使函数声明为
constexpr,也会退化为普通运行时函数 - 示例:
constexpr int square(int x) { return x * x; }在int a[square(5)];中有效,在int b[square(n)];(n是运行时变量)中无效,但不会导致编译失败(只是不参与常量表达式)
常见误用与陷阱
看似写了 constexpr,实际并未达成编译期求值,甚至引发未定义行为:
立即学习“C++免费学习笔记(深入)”;
- 对非字面类型(non-literal type)使用
constexpr:例如含虚函数、用户自定义构造函数且未标记constexpr的类,无法声明为constexpr对象 - 引用或指针指向运行时地址:
constexpr const int* p = &x;合法仅当x是constexpr变量且生命周期延伸到常量表达式求值期间;否则报错 - 调用未定义行为的
constexpr函数(如除零、越界访问):C++14 起这类函数在常量表达式中调用会直接导致编译失败(SFINAE 或硬错误),而非静默忽略 - 忽略隐式转换:比如
constexpr double d = 3.14;不能用于需要整型常量表达式的地方(如数组大小),即使数值上是整数
最易被忽略的一点:一个 constexpr 函数是否真正在编译期执行,完全取决于**调用上下文**,而不是函数声明本身。编译器不会为你“尽力优化”,它只按标准判断能否静态求值——写错了,就报错;写对了,但用在运行时变量上,它就老老实实生成运行时代码。











