C++ Logo


Advanced search

Re: Not understanding rvalue reference matching rules in overloaded functions.

From: Andrew Schepler <aschepler_at_[hidden]>
Date: Tue, 1 Jun 2021 12:31:06 -0400
On Tue, Jun 1, 2021 at 9:55 AM Edward Diener via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> The code:
> #include <iostream>
> #include <utility>
> void afunc(int)
> {
> std::cout << "\nafunc(int)\n";
> }
> void afunc(int &&)
> {
> std::cout << "\nafunc(int &&)\n";
> }
> int main()
> {
> int i = 0;
> afunc(std::move(i));
> }
> The result is an error saying that the call to 'afunc' is ambiguous.
> Since std::move creates an rvalue reference and one of the overloads to
> afunc takes an rvalue reference, for an exact match, I do not understand
> the error. Would someone please explain and cite the section of the
> C++11 standard which explains why the exact match is an equal match to
> the other overload, thereby causing ambiguity ?
Summary: Both conversion sequences are the identity conversion, and none of
the special cases where value category and reference parameters do rank
overloads apply.

First, note that an expression effectively never has a reference type per
[expr]/5. std::move(i) is an xvalue which has type int.

If we call "void afunc(int)" = F1 and "void afunc(int&&)" = F2, then
ICS1(F1) is the identity conversion since no other row in
[over.ics.scs]/3's Table 12 applies. For F2, note [over.ics.ref]/1: "When a
parameter of reference type binds directly (8.5.3) to an argument
expression, the implicit conversion sequence is the identity conversion,
unless the argument expression has a type that is a derived class of the
parameter type, in which case...." Since initialization of the reference
parameter does not require a temporary object, the parameter does "bind
directly", and ICS1(F2) is also the identity conversion.

Additional rules for ranking implicit conversion sequences involving
references are found in [over.ics.rank]. Paragraph 3 lists:

> Two implicit conversion sequences of the same form are indistinguishable
conversion sequences unless one of the following rules applies:
> - Standard conversion sequence S1 is a better conversion sequence S2 if
> - S1 is a proper subsequence of S2 (comparing the conversion sequences
in the canonical form defined by, excluding any Lvalue
Transformation; the identity conversion sequence is considered to be a
subsequence of any non-identity conversion sequence) or, if not that,
> - the rank of S1 is better than the rank of S2, or S1 and S2 have the
same rank and are distinguishable by the rules in the paragraph below, or,
if not that,
> - S1 and S2 differ only in their qualification conversion and ...
> - S1 and S2 are reference bindings (8.5.3) and ...
> - S1 and S2 are reference bindings (8.5.3) and ...
> - S1 and S2 are reference bindings (8.5.3), and ...
> - User-defined conversion sequence U1 is a better conversion sequence
than another user-defined conversion sequence U2 if ...
> - List-initialization sequence L1 is a better conversion sequence than
list-initialization sequence L2 if ...

(Yes, the repeated "reference bindings" bullets are intentional; the parts
after "and" are different.) In the context, "same form" only means that the
implicit conversion sequences are both standard conversion sequences, or
both user-defined conversion sequences, or both ellipsis conversion
sequences. (Note every well-formed list-initialization sequence is also
either a standard conversion sequence or user-defined conversion sequence,
per [over.ics.list].)

None of these points apply, so ICS1(F1) and ICS2(F2) are indistinguishable,
and overload resolution for the functions is ambiguous.

-- Andrew Schepler

Received on 2021-06-01 11:31:22