C++ Logo

std-discussion

Advanced search

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

From: jim x <xmh970252187_at_[hidden]>
Date: Thu, 31 Dec 2020 09:47:31 +0800
I think you misread the section [dcl.init.ref]. your example should be
processed by the paragraph [dcl.init.ref#5.4.1]
<https://eel.is/c++draft/dcl.init.ref#5.4.1>. So, why you uncomment the
other function then that would be the best? Because the reference be
initialized is a lvalue reference, which should be first processed by the
paragraph [dcl.init.ref#5.1.2] <https://eel.is/c++draft/dcl.init.ref#5.1.2> and
in this case, the candidate functions are formed by [over.match.ref#1.1.1]
<https://eel.is/c++draft/over.match.ref#1.1.1>. And the set
constitutes only one member which is `operator const int &() const &;`.

Lénárd Szolnoki via Std-Discussion <std-discussion_at_[hidden]>
于2020年12月31日周四 上午12:18写道:

> Hi,
>
> On Wed, 30 Dec 2020 13:48:17 +0800
> jim x via Std-Discussion <std-discussion_at_[hidden]> wrote:
>
> > For your first example, the parameter of the first function is of
> > type `int` and the corresponding argument has type `S`, Hence, the
> > following rules apply here:
> > > Otherwise, if the source type is a (possibly cv-qualified) class
> > > type,
> > conversion functions are considered. The applicable conversion
> > functions are enumerated (*[over.match.conv]*), and the best one is
> > chosen through overload resolution.
> > Through look at the rule in [over.match.conv], the candidate
> > functions are formed by:
> > > The conversion functions of S and its base classes are considered.
> > > Those
> > non-explicit conversion functions that are not hidden within S and
> > *yield type T or a type that can be converted to type T via a
> > standard conversion sequence* are candidate functions.
> >
> > Hence, `operator int() const &` and `operator char() &&` are all
> > candidate functions, in order to determine which is the best, hence
> > the overload resolution applies here to find out the best, in the
> > first candidate function, the implicit parameter object type is `S
> > const&`. Rather, the implicit parameter object type of the second
> > candidate is `S&&`. In this case, the argument is of type `S` and a
> > prvalue. According to: [over.ics.rank#3.2.3]
> > >S1 and S2 are reference bindings ([dcl.init.ref]) and neither refers
> > >to an
> > implicit object parameter of a non-static member function declared
> > without a ref-qualifier, and S1 binds an rvalue reference to an
> > rvalue and S2 binds an lvalue reference.
> >
> > `operator char() &&` wins the game.
> > And according to:
> > >The effect of any implicit conversion is the same as performing the
> > corresponding declaration and initialization and then using the
> > temporary variable as the result of the conversion. The result is an
> > lvalue if T is an lvalue reference type or an rvalue reference to
> > function type ([dcl.ref]), an xvalue if T is an rvalue reference to
> > object type, and a prvalue otherwise. The expression e is used as a
> > glvalue if and only if the initialization uses it as a glvalue.
> >
> > That means `char tmp = S{};` where the `tmp` is used as the argument
> > in function call. A similar process undergoes for `void foo(char)`.
> > Now, the first example can be simplified to when the argument is of
> > type `char`, which function is the best when calling foo(tmp).
> > Certainly, it is `void foo(char)`.
> >
> > Now, let us consider the second example.
> > Arguably, it is different from the first example. the parameter of
> > `void foo(const int &)` is of type `int const&`. So [dcl.init.ref]
> > applies here. According to [dcl.init.ref#5.1.2]
> > <https://timsong-cpp.github.io/cppwp/n4659/dcl.init.ref#5.1.2> and
> > [over.match.ref#1.1]
> > <https://timsong-cpp.github.io/cppwp/n4659/over.match.ref#1.1>, all
> > functions that have return type of lvalue reference to type T are
> > candidate functions, here only `operator const int &() const &` is.
>
> In my reading `operator int&&() &&` should also be a candidate, as
> rvalue returning conversion functions are also candidates. In case it's
> the only candidate it seems to be selected just fine:
>
> https://godbolt.org/z/8Wo6se
>
> However if the other conversion function is uncommented then that one
> is deemed better by all compilers, even though I would expect the
> rvalue ref qualified one to be better according to
> [over.ics.rank#3.2.3], similarly to the first example.
>
> > And from the type of this conversion to `const int &` has an
> > identity conversion. Instead, for the second `void foo(int &&)`, the
> > candidate conversion function is only `operator int &&() &&` per
> > [dcl.init.ref#5.2.1.2]
> > <https://timsong-cpp.github.io/cppwp/n4659/dcl.init.ref#5.2.1.2> and
> > [over.match.ref#1.1]. From the result of `operator int &&() &&` to
> > `int &&` is also an identity conversion. Hence, your second example
> > gives an ambiguous error.
> >
> >
> > Hani Deek via Std-Discussion <std-discussion_at_[hidden]>
> > 于2020年12月30日周三 上午5:05写道:
> >
> > > 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 && '.
> > >
> > > --
> > > Std-Discussion mailing list
> > > Std-Discussion_at_[hidden]
> > > https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
> > >
>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>

Received on 2020-12-30 19:47:46