C++ Logo

std-discussion

Advanced search

Re: Why does overload resolution fail in this simple case?

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Wed, 30 Dec 2020 00:51:32 +0000
Hi,

On Tue, 29 Dec 2020 21:04:34 +0000
Hani Deek via Std-Discussion <std-discussion_at_[hidden]> wrote:

> Hello,
>
>
> With MSVC, the following code compiles. The char overload is selected
> by overload resolution.
>
> struct S
> {
> operator int() const & { return 0; }
> operator char() && { return 0; }
> };
>
> void foo(int) {}
> void foo(char) {}
>
> int main()
> {
> foo(S{}); //OK, calls 'void foo(char)'.
> }
>
>
> However, the following code won't compile.
>
> struct S
> {
> int i = 0;
> operator const int &() const & { return i; }
> operator int &&() && { return (int &&)(i); }
> };
>
> void foo(const int &) {}
> void foo(int &&) {}
>
> int main()
> {
> foo(S{}); //error C2668: 'foo': ambiguous call to overloaded
> function //message : could be 'void foo(int &&)'
> //message : or 'void foo(const int &)'
> }
>
>
> What is exactly the difference that makes the second sample fail to
> compile?
>
> Given that 'operator int &&() &&' is an exact match to the conversion
> required to call 'void foo(int &&)', I expected the compiler to
> select it. It is strange if the C++ rules will not allow the compiler
> to select a conversion function that exactly matches the required
> conversion, both in terms of the provided argument 'S &&' and the
> result of conversion 'int &&'.
>

It's interesting that the two example differs, but I'm even more
interested in why the first example compiles.

https://godbolt.org/z/KWefnf

In my reading of the standard wording both examples should be
ill-formed, but all compilers seem to disagree with me on the first

The context is overload resolution between `void foo(int)` and `void
foo(char)` for the expression `foo(S{})`. Both candidates have a
user-defined conversion sequence for the argument, with distinct
user-defined conversion function selected. It makes these conversions
sequences indistinguishable.

http://eel.is/c++draft/over.ics.rank#3.sentence-1
http://eel.is/c++draft/over.ics.rank#3.3

I don't see an exemption for unordered implicit conversion sequences in
http://eel.is/c++draft/over.match.best#general-2 that would make any of
the `foo` candidates better than the other.

http://eel.is/c++draft/over.match.best#general-2.2 seems close, but I
don't think that applies.

I must miss something obvious (likely), or all the compilers are wrong
on this one.

Cheers,
Lénárd

Received on 2020-12-29 18:51:40