在 C 中,常量表达式是在编译时计算的数学表达式。在评估这些表达式时,必须处理可能发生未定义行为 (UB) 的情况。
C 标准在第 5.19 节中明确规定了对未定义行为的排除核心常量表达式:
“...具有未定义行为的操作 [...] 不是
此排除子句有两个主要目的:
考虑以下表达式:
constexpr int x = std::numeric_limits<int>::max() + 1;
如果没有排除子句,该表达式将被视为常量表达式,因为它不涉及任何显式排除的操作。然而,由于整数溢出,它仍然会表现出 UB。
排除子句允许编译器在编译时检测到此 UB,如下所示:
error: constexpr variable 'x' must be initialized by a constant expression constexpr int x = std::numeric_limits<int>::max() + 1 ;
排除子句还允许在 SFINAE(替换失败不是错误)中使用常量表达式来确定表达式是否会在编译时导致 UB。例如,下面的代码片段说明了如何检测整数加法溢出:
template <typename T1, typename T2> struct addIsDefined { static constexpr bool isDefined() { return isDefinedHelper<T1, T2>(0); } template <T1 t1, T2 t2, decltype(t1 + t2) result = t1 + t2> static constexpr bool isDefinedHelper(int) { return true; } template <T1 t1, T2 t2> static constexpr bool isDefinedHelper(...) { return false; } };
总之,常量表达式中未定义行为的排除子句的存在允许编译器在编译时检测 UB,从而促进开发更安全、更可靠的代码。
以上是为什么 C 从常量表达式中排除未定义的行为?的详细内容。更多信息请关注PHP中文网其他相关文章!