constexpr函数必须满足编译期可求值约束:参数与返回类型为字面类型、函数体无运行时操作、调用实参为常量表达式;c++14起支持循环与分支,但递归深度受限;consteval更严格,仅限编译期求值。

constexpr 函数必须满足编译期可求值的约束
不是所有函数加个 constexpr 就能进编译期——它本质是“编译器承诺能算出来”的契约。一旦函数体里出现运行时才确定的值(比如 std::cin、new、未初始化的局部变量),哪怕只在某条分支里,整个函数就退化为普通函数,constexpr 失效。
- 返回类型和所有参数类型必须是字面类型(
int、std::string_view、自定义类需有constexpr构造函数等) - C++14 起允许函数体内含有限循环和条件分支,但 C++11 只支持单个
return表达式 - 调用时传入的实参必须是常量表达式(如字面量、
constexpr变量),否则触发编译错误:error: the value of 'x' is not usable in a constant expression
怎么写一个真正能在编译期展开的 constexpr 函数
核心是“只依赖已知输入 + 无副作用”。比如计算阶乘:
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}这个函数在 C++14+ 下合法,但要注意:
- 不能写
if (n > 10) throw std::logic_error("too big")—— 异常抛出不是常量表达式操作 - 避免递归过深:编译器有深度限制(GCC 默认 512 层),超限报错:
error: constexpr evaluation depth exceeds maximum - 若想支持更大输入,改用迭代写法(C++20 起支持
constexpr循环)
constexpr 函数被当成运行时函数调用的常见原因
明明写了 constexpr,结果生成的汇编里还是调用了函数?大概率是调用上下文没满足常量表达式要求。
立即学习“C++免费学习笔记(深入)”;
- 用非常量变量调用:
int x = 5; auto v = factorial(x);→ 运行时调用 - 数组长度声明时用了非
constexpr结果:int arr[factorial(5)];合法;但int y = 5; int arr2[factorial(y)];非法(C++14 起部分编译器可能接受,但非标准) - 模板非类型参数中使用:
template<int n> struct X {}; X<factorial> x;</factorial></int>必须确保factorial(4)在实例化点是常量表达式
constexpr 和 consteval 的关键区别在哪
consteval 是 C++20 新增的,意思是“必须在编译期求值”,比 constexpr 更严格。
-
constexpr函数可以既用于编译期,也用于运行时;consteval函数只能用于编译期,任何运行时调用直接编译失败 - 比如
consteval int square(int x) { return x * x; },写int a = 3; square(a);会报错:error: call to consteval function 'square' is not a constant expression - 别为了“显得更编译期”滥用
consteval——它会破坏函数复用性,仅当逻辑上绝对不允许运行时执行时才用
最易忽略的是:constexpr 函数的“编译期能力”不传递给它的调用者——你得逐层检查每一步输入是否真的常量,而不是看到函数名带 constexpr 就默认安全。










