8
votes

The following code compiles fine on all compilers I've checked (clang, mingw, g++) other than 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 fails with the following error:

>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)'

Any insight would be great, I've been scratching my head about this all day.

My version of MSVC is 14.0 however I've tested it online with version Version 19.00.23506 and the same error appears.

The error does not apear with version 19.11.25331.0 however. Compiler bug then?

1
Probably because there's the built-in one. - StoryTeller - Unslander Monica
As a side note, I would be confused if I had to use your version of operator== because it does not test equality. - piwi
@piwi - it's just the minimum code to reproduce the ambiguous error, - hippiemancam
@hippiemancam Oh ok, my bad. - piwi
@StoryTeller That seems reasonable, how does one override this built-in? Also, any ideas why only MSVC throws the error when nothing else even has warnings? - hippiemancam

1 Answers

7
votes

For enumerations, there's a built-in comparison operator. When you define yours, the built-in is supposed to be hidden automatically.

[over.built/1]

The candidate operator functions that represent the built-in operators defined in Clause [expr] are specified in this subclause. These candidate functions participate in the operator overload resolution process as described in [over.match.oper] and are used for no other purpose. [ Note: Because built-in operators take only operands with non-class type, and operator overload resolution occurs only when an operand expression originally has class or enumeration type, operator overload resolution can resolve to a built-in operator only when an operand has a class type that has a user-defined conversion to a non-class type appropriate for the operator, or when an operand has an enumeration type that can be converted to a type appropriate for the operator. Also note that some of the candidate operator functions given in this subclause are more permissive than the built-in operators themselves. As described in [over.match.oper], after a built-in operator is selected by overload resolution the expression is subject to the requirements for the built-in operator given in Clause [expr], and therefore to any additional semantic constraints given there. If there is a user-written candidate with the same name and parameter types as a built-in candidate operator function, the built-in operator function is hidden and is not included in the set of candidate functions. — end note ]

To answer your question, yes, it seems like a compiler bug.