我最近处理了使用包含负值的强类型枚举的代码。当比较枚举的值时,我在用Clang(3.3)编译代码时得到了奇怪的结果,而Gcc运行得很好。
下面是一个断言失败的小例子。
enum class T: int { A = -1, B = 1 };
int main() {
T a = T::A, b = T::B;
assert(a < b);
}
这是一个真正的bug吗?或者clang的行为是否正确,而gcc只是提供了某种遗留支持?
应该更直观的是,以下是格式良好的:
T a = T::A;
assert(a == T::A);
但是相等运算符(==
,!=
)与关系运算符(<
,<=
,..)具有相同的限制[expr.eq]/1:
==
(等于)和!=
(不等于)运算符具有与关系运算符相同的语义限制、转换和结果类型,只是它们的优先级和真值结果较低。
因此,如果定义了作用域枚举类型的值之间的相等性,那么<
也应该是.
[expr.rel]/1
操作数应具有算术、枚举或指针类型,或类型
std::nullptr_t
。
当然,通常的算术转换是对算术或枚举类型[expr.rel]/2的操作数执行的,其中转换是作用域枚举的身份转换(没有积分提升,请参见[expr]/10第一个项目符号)。然而,[expr.rel]/5明确指出:
如果两个操作数(转换后的)都是算术或枚举类型,则每个操作数应产生如果指定的关系为真则为
true
,如果为假则为false
。
(重点矿井)
因此,T::A < T::B
应形成良好的,产生true
。
正如我在评论中所写的,clang++3.4 trunk 193040上的断言没有失败。因此,我认为这是一个已经修复的错误,尽管我找不到相应的错误报告。