为什么在MSVC中枚举类型的==运算符重载存在歧义

8
以下代码在我检查过的所有编译器(clang,mingw,g++)中都可以正常编译,但在MSVC上无法编译。
enum class Foo{BAR};

bool operator==(Foo a, Foo b)
{
    return (int)a & (int)b;
}

int main(int argc, char *argv[])
{
    Foo::BAR==Foo::BAR;
    return 0;
}

MSVC出现以下错误:

>main.cpp(10): error C2593: 'operator ==' is ambiguous
>main.cpp(3): note: could be 'bool operator ==(Foo,Foo)'
>main.cpp(10): note: while trying to match the argument list '(Foo, Foo)'

任何见解都是宝贵的,我已经为此烦恼了一整天。 我的 MSVC 版本是 14.0,但我已经使用 19.00.23506 版本进行了在线测试,出现了相同的错误。 然而,在版本 19.11.25331.0 中并没有出现这个错误。 难道是编译器的 bug?

6
可能是因为有内置的一个。 - StoryTeller - Unslander Monica
1
顺便提一下,如果我必须使用你的 operator== 版本,我会感到困惑,因为它并没有测试相等性。 - piwi
@piwi - 这只是最少的代码来重现这个模棱两可的错误。 - hippiemancam
@hippiemancam 哦,好的,我的错。 - piwi
@StoryTeller 这听起来很合理,如何覆盖这个内置的东西?还有,为什么只有 MSVC 抛出错误,而其他任何东西甚至没有警告呢? - hippiemancam
@hippiemancam - 像你所做的那样覆盖它(请参见我的答案)。MSVC 抱怨是错误的。你的匹配更好。 - StoryTeller - Unslander Monica
1个回答

7
对于枚举类型,有一个内置的比较运算符。当你定义自己的时候,内置的应该会自动隐藏。

[over.built/1]


此子句规定了代表条款 [expr] 中定义的内置运算符的候选运算符函数。这些候选函数参与重载运算符解析过程,如 [over.match.oper] 中所述,并且不用于其他目的。[注意:由于内置运算符仅接受具有非类类型的操作数,并且仅当操作数表达式最初具有类或枚举类型时才发生运算符重载决议,因此只有在具有用户定义的转换为适合运算符的非类类型的类类型或可以转换为适合该运算符的类型的枚举类型的操作数存在时,运算符重载决议才会解析为内置运算符。还要注意,此子句中提供的某些候选运算符函数比内置运算符本身更宽松。如 [over.match.oper] 中所述,在使用重载决议选择内置运算符后,表达式将遵循条款 [expr] 中规定的内置运算符要求以及其中给出的任何其他语义约束。如果存在与内置候选运算符函数具有相同名称和参数类型的用户编写的候选运算符,则隐藏内置运算符函数并不包括在候选函数集中。]
回答你的问题,是的,看起来像是编译器的一个bug。

谢谢你,知道我不是疯了真是太好了。 - hippiemancam
@T.C. - 引用的段落错误(现已更正),但编译器仍有漏洞。 - StoryTeller - Unslander Monica
好多了。但请注意,隐藏是基于精确类型匹配的,可能会很脆弱:bool operator==(const Foo&, const Foo&); 不会隐藏内置函数。 - T.C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接