C++ Logo

STD-DISCUSSION

Advanced search

Subject: Re: Why does overload resolution fail in this simple case?
From: jim x (xmh970252187_at_[hidden])
Date: 2020-12-30 09:11:08


Your suggestion is similar with [over.match.best#general-2.3]
<https://eel.is/c++draft/over.match.best#general-2.3>. However, for your
second example, I think it's necessary to be ambiguous. Compare two
different user-defined conversions does not make sense, which is the intent
of [over.ics.rank#3.3] <https://eel.is/c++draft/over.ics.rank#3.3>. Except
for that, two user-defined conversion sequences are indistinguishable.

Hani Deek via Std-Discussion <std-discussion_at_[hidden]>
于2020年12月30日周三 下午9:32写道:

> Thanks jim x for clearing it up, and thanks to Lénárd Szolnoki for his
> valuable contribution.
> I do not claim to have great experience with the C++ standard, but I
> humbly feel that this issue exposes a deficiency in 12.2.4.3
> [over.ics.rank]. If two user-defined conversion sequences use two different
> user-defined conversion functions, then I think it makes sense to rank as
> better the user-defined conversion function whose ref-qualifier is a closer
> match to the value category of the object being converted.
>
> In my example, I think it is logical to rank 'operator int &&() &&' as
> better than 'operator const int &() const &', because the object that is
> being converted is a prvalue.
>
> ------------------------------
> 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. 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
>



STD-DISCUSSION list run by std-discussion-owner@lists.isocpp.org

Older Archives on Google Groups