归一化函数必须拆成编译期与运行时两个分支,因为std::sqrt等函数在C++20前非constexpr,混写会导致编译失败或精度丢失;编译期需用constexpr变量和字面量匹配直接折叠,运行时才调用浮点运算与三角函数。

必须用 std::is_constant_evaluated() 区分编译期与运行时路径,否则同一函数在几何库中会因求值时机不同而崩溃或退化——它不是可选项,是双模实现的强制约束。
为什么归一化函数必须拆成两个逻辑分支
向量归一化在编译期已知长度时应直接折叠为比例系数(如 vec / 2.0),但运行时必须调用 std::sqrt 和浮点除法。混写会导致编译失败或运行时精度丢失。
-
std::sqrt在 C++20 及之前不是constexpr,放进编译期分支会触发硬错误 - 若只写运行时逻辑,
constexpr vec3 v = normalize({3, 4, 0});就无法通过,失去编译期常量折叠能力 - 中间变量(如长度平方)在编译期分支中必须声明为
constexpr double len2 = x*x + y*y + z*z;,不能依赖运行时初始化
齐次变换矩阵如何避免编译期调用 std::sin/std::cos
绕固定角度(如 π/2)旋转时,编译期应直接返回预置 constexpr std::array;运行时才调用三角函数。错放会直接中断编译。
- 编译期分支里只能用
constexpr switch或if链匹配字面量角度(如if constexpr (angle == 1.57079632679)),不能对任意double参数做数值比较 -
std::sin(angle)出现在if (std::is_constant_evaluated())内 → 编译失败,GCC/Clang 均报 “call to non-constexpr function” - 运行时分支可自由使用
std::vector缓存常见角度表,但该表绝不能被编译期分支引用
静态场景的 AABB 树构建为何依赖输入是否为 constexpr
几何体数组若在编译期已知(如 constexpr std::array),包围盒层级可完全展开并剔除空节点;否则必须运行时递归构建。
- 输入必须作为模板参数或
constexpr容器传入,普通const std::vector无法触发编译期路径& - 编译期分支内禁止任何动态内存操作:不能
new节点,不能调用std::vector::push_back,连取地址都受限(不能取非常量全局变量地址) - 查表逻辑可放入编译期分支,但表本身必须是
constexpr std::array,且索引计算全程可常量折叠
最容易被忽略的是:std::is_constant_evaluated() 的返回值不取决于函数声明,而取决于调用点是否构成常量表达式——static_assert(normalize(v) == expected); 能过,constexpr auto r = normalize(v); 却可能失败,因为后者未必被编译器判定为强制常量求值上下文。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











