Resolution of built-in operator == overloads
Asked Answered
J

1

11

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?

Jhansi answered 21/1, 2022 at 18:5 Comment(7)
Based on the diagnostic alone I think this must be a Clang bug. Why would it try to use a float comparison here at all?Christogram
Is this C++20 ?Mexicali
@TedLyngmo That's what linked demo is using at least.Christogram
@Christogram Thanks. I was thinking of the language-lawyer tag and if the version should be added to the question. Perhaps it's the same issue in all versions but wasn't there a change in C++20 w.r.t. operator overloading? I seem to remember something about it adding implicit overloads for rhs, lhs if lhs, rhs has been defined ... but ... hmm, sounds scary. I probably remember wrong.Mexicali
@TedLyngmo Yeah, there have definitely been changes in how comparisons work in C++20, though in this case the compiler variance exists even in C++17, so I don't think the tag is necessary here.Christogram
@TedLyngmo nothing new, happens all the way back to clang 3.0.0Hound
Maybe also relevant: If instead of == normal function overloads f(float, int) and f(int, int) are considered in a call f(A{}, 2), then GCC agrees that it is ambiguous, while MSVC still accepts.Nahuatlan
C
14

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.

Chitter answered 21/1, 2022 at 19:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.