在 C++ 中,表达式 ~true 并不会像人们期望的简单位翻转那样得到 false。相反,语言在执行补位操作之前会将 bool 值提升为整数类型。值 true(1)变为 int,其按位补在二进制补码下是 –2,而将该 int 再转回 bool 时遵循布尔转换规则:任何非零值变为 true。因此 static_cast<bool>(~true) 的求值结果为 true,这一点在主要来源中通过对应的汇编输出得到了验证。
当相同的操作应用于具有底层 bool 类型并带有 [[std::bitmask_type]] 注释的作用域枚举时,根据标准的预期结果同样是 true。该枚举的按位补运算符首先将枚举转换为其底层 bool,再提升该 bool 为 int,计算补位(‑2),随后将 int 再转换回枚举类型。Clang 和 MSVC 在最终转换时应用布尔转换规则,得到 true。然而,GCC 出现偏差:它在转换之前将 int 值截断为最低位(‑2 → 0),从而得到 false。主要来源记录了这一差异,并展示了两种行为的不同 Godbolt 链接。
一个相关的陷阱在于没有固定底层类型的无作用域枚举。此时补位运算符可能产生超出枚举可表示范围的值,而将该值转换回枚举类型会引发未定义行为。例如,枚举 enum nums {zero, one, two, three} 具有 unsigned int 底层类型;~one 的结果为 int 类型的 ‑2,但将 ‑2 转换回 nums 超出范围,标准将其标记为未定义行为。主要来源解释了这一风险,并指出此问题仅影响没有显式底层类型的普通枚举,因为作用域枚举以及具有固定底层类型的枚举继承了明确定义的范围。
