constexpr函数仅在满足三个条件时才编译期求值:函数声明为constexpr、所有实参为常量表达式、调用上下文要求常量表达式;否则退化为运行时调用。

constexpr函数不是编译期强制执行的
它只在满足特定条件时才被编译器“选择”在编译期求值,否则就退化为普通运行时函数。很多人误以为加了 constexpr 就一定进编译期,结果 static_assert 报错或数组大小不合法,根源就在这里。
必须同时满足三个条件才能触发编译期执行
缺一不可,否则编译器直接跳过编译期路径:
- 函数本身被声明为
constexpr(语法正确) - 所有实参都是常量表达式(如字面量、
constexpr变量、其他编译期可算出的值) - 调用上下文要求常量表达式(比如用于数组长度、模板非类型参数、
static_assert断言、constexpr变量初始化等)
例如:constexprintx = square(5); 满足全部三条;而 intruntime = 5; constexprinty = square(runtime); 第二条失败,y 声明非法(C++11/C++14)或退化为运行时调用(C++17 起允许但不能用于常量上下文)。
常见踩坑点:参数看似是常量,实则不是
这些写法看着像编译期常量,但实际不是,会导致编译失败或静默退化:
立即学习“C++免费学习笔记(深入)”;
-
constinta = 42;——a是运行时常量,不是 常量表达式,不能传给需要编译期求值的constexpr函数调用上下文 -
extern constexpr int N = 10;—— 若定义在别处且未内联,链接期才可见,多数编译器拒绝在当前 TU 当作编译期常量使用 - 成员函数返回值没标
constexpr,即使对象是constexpr的,调用obj.getValue()仍无法参与编译期计算 - C++11 中浮点数参数受限,
constexpr double f(double x)在 C++11 不被允许(C++14 起放开)
验证是否真正在编译期执行的最简单方法
别靠猜,用两个硬性信号判断:
- 能放进
static_assert:例如static_assert(factorial(4) == 24, "");—— 成功即证明编译期算出了 24 - 能用作数组维度:
int arr[factorial(4)];—— 若编译通过,说明factorial(4)确实是编译期整型常量
只要其中一个失败,就说明该次调用没走编译期路径——这时候要回溯检查参数来源和上下文约束,而不是怀疑函数写得不够“constexpr”。


















