In the following code struct A
has two implicit conversion operators to char
and int
, and an instance of the struct is compared for equality against integer constant 2
:
struct A {
constexpr operator char() { return 1; }
constexpr operator int() { return 2; }
};
static_assert( A{} == 2 );
The code passed fine in GCC and MSVC, but Clang complains:
<source>:5:20: error: use of overloaded operator '==' is ambiguous (with operand types 'A' and 'int')
static_assert( A{} == 2 );
~~~ ^ ~
<source>:5:20: note: because of ambiguity in conversion of 'A' to 'float'
<source>:2:15: note: candidate function
constexpr operator char() { return 1; }
^
<source>:3:15: note: candidate function
constexpr operator int() { return 2; }
^
<source>:5:20: note: built-in candidate operator==(float, int)
static_assert( A{} == 2 );
^
<source>:5:20: note: built-in candidate operator==(double, int)
<source>:5:20: note: built-in candidate operator==(long double, int)
<source>:5:20: note: built-in candidate operator==(__float128, int)
<source>:5:20: note: built-in candidate operator==(int, int)
...
Demo: https://gcc.godbolt.org/z/h9Kd66heM
The general question is which compiler right here? And in particular it is interesting to know why Clang does not prefer operator==(int, int)
, however lists it among others?
This is CWG 507. An example similar to yours was given, and the submitter explained that according to the standard, the overload resolution is ambiguous, even though this result is very counter-intuitive.
Translating to your particular example, when comparing operator==(int, int)
and operator==(float, int)
to determine which is the better candidate, we have to determine which one has the better implicit conversion sequence for the first argument (obviously in the second argument, no conversion is required). For the first argument of operator==(int, int)
, we just use A::operator int
. For the first argument of operator==(float, int)
, there is no way to decide whether to use A::operator int
or A::operator char
, so we get the "ambiguous conversion sequence". The overload resolution rules say that the ambiguous conversion sequence is no better or worse than any other user-defined conversion sequence. Therefore, the straightforward conversion from A{}
to int
(via A::operator int
) is not considered better than the ambiguous conversion from A{}
to float
. This means neither operator==
candidate is better than the other.
Clang is apparently following the letter of the standard whereas GCC and MSVC are probably doing something else because of the standard seeming to be broken here. "Which compiler is right" depends on your opinion about what the standard should say. There is no proposed resolution on the issues page.
I would suggest removing operator char
unless you really, really need it, in which case you will have to think about what else you're willing to give up.