std::is_constant_evaluated() 是编译期安全开关而非可选优化:它强制区分 constexpr 与运行时路径,分支内仅允许 c++20 常量表达式操作,否则直接编译失败;普通变量初始化中恒返回 false,仅 static_assert 或变长数组等强制常量上下文才触发编译期路径。

它不是“可选优化”,而是双模几何函数的编译期安全开关:不加 std::is_constant_evaluated(),同一函数在 constexpr 上下文里必然编译失败。
为什么归一化函数必须用 if (std::is_constant_evaluated()) 分支
向量归一化 v / std::sqrt(x*x + y*y + z*z) 在编译期已知长度时应直接折叠为比例系数(如 v / 5.0),但 std::sqrt 在 C++20 及之前根本不是 constexpr 函数。混写会导致硬编译错误,而非静默退化。
- 编译期分支里写
return v / std::sqrt(len2);→ GCC/Clang 直接报 “call to non-constexpr function” - 正确做法:编译期分支只用
constexpr double len2 = x*x + y*y + z*z;+ 手工近似(如小整数查表)或 C++23 的std::sqrt(需-std=c++23) - 运行时分支才调用
std::sqrt、std::hypot,并加入 NaN 检测和异常处理 - 中间变量如
len2必须显式声明为constexpr double,否则编译器无法保证其常量性
齐次变换矩阵如何避免编译期调用 std::sin/std::cos
绕固定角度(如 π/2)构造旋转矩阵时,编译期路径必须返回字面量 std::array,绝不能让 std::sin 或 std::cos 出现在 if (std::is_constant_evaluated()) 分支内——它们在绝大多数标准下都不是 constexpr。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 编译期分支只允许对字面量角度做
if constexpr (angle == 1.5707963267948966)或constexpr switch判断 - 运行时分支才调用
std::sin(angle)、std::cos(angle)并填充std::array - 禁止在编译期分支中定义
std::vector缓存角度表——哪怕没用到,代码存在即违法 - 典型误用:
constexpr auto s = std::sin(angle);放在 true 分支里 → 编译失败,错误位置就指向这行
为什么 std::is_constant_evaluated() 在普通变量初始化里永远返回 false
它不看参数是不是字面量,也不看你有没有写 constexpr 函数签名,只看“这次调用是否被上下文明确要求是常量表达式”。普通变量初始化不强制求值,所以分支根本进不去。
-
int x = normalize({3, 4, 0});→std::is_constant_evaluated()返回false,走运行时分支 -
static_assert(normalize({3, 4, 0}) == expected);或int arr[normalize({3, 4, 0})];→ 才可能触发编译期路径 -
const int y = normalize({3, 4, 0});不等于constexpr,标准不要求走编译期,GCC/Clang 均返回false - 唯一可靠验证方式:用
static_assert或变长数组测试;通不过,说明没进编译期
编译期分支里哪些操作会直接导致编译失败
一旦进入 if (std::is_constant_evaluated()) 分支,所有语句都必须满足 C++20 常量求值规则。常见非法操作不是“性能差”,而是“语法上不允许”。
- 调用
std::strlen、std::printf、std::sqrt(C++20 前)等非 constexpr 函数 - 使用
new、delete(C++23 部分支持但 GCC 14/Clang 17 仍限制严格) - 读取非常量全局变量、未初始化的
static变量,或对局部变量取地址(除非该变量生命周期可静态验证) - 调用非 constexpr 成员函数,或使用
std::vector::push_back(即使 C++23 允许,GCC 14 仍拒绝非 trivial 类型) - 安全替代:把编译期逻辑抽成独立
constexpr辅助函数,主函数只做跳转
最容易被忽略的是:它的行为高度依赖调用点上下文,而非函数本身。同一个 normalize 调用,在 static_assert 里成功,在 constexpr auto r = ... 里却可能失败——因为后者未必被编译器判定为强制常量求值上下文。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










