Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array-to-pointer conversion + rvalue-ref: Overload resolution difference GCC vs clang

#include <iostream>
#define FUNC() { std::cout << __PRETTY_FUNCTION__ << "\n"; }

void foo(char const*&&   ) FUNC() // A
void foo(char const(&)[4]) FUNC() // B

int main()
{
    foo("bar");
}

Demo

When using an rvalue reference in the parameter type of the first overload (A), clang current master unambiguously chooses that overload A over B. GCC current master on the other hand complains about an ambiguity.

I'm quite surprised that the string literal, being an lvalue of 4 char const ([expr.prim.literal]/1, [lex.string]/6) should prefer the array-to-pointer conversion on overload A over the identity conversion on overload B.

Without the rvalue reference, that is void foo(char const*), both GCC and clang reject the call as ambiguous. That's also something I don't fully understand, since I would have guessed that there's still an array-to-pointer conversion and therefore [over.ics.rank]p3.2.1 applies:

  • Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

    • (3.2.1) S1 is a proper subsequence of S2 (comparing the conversion sequences in the canonical form defined by [over.ics.scs], excluding any Lvalue Transformation; the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence) or, if not that,

What is going on in either case?

like image 778
dyp Avatar asked Jan 13 '21 15:01

dyp


1 Answers

(This is only a partial answer, covering the second case)

What is going on in either case?

Regarding the second case, as to why the following overloads

void foo(char const*     ) FUNC() // A
void foo(char const(&)[4]) FUNC() // B

yields ambiguous overloads (for both Clang and GCC); [over.ics.rank]/3.2.1 may seem to favour B, being an identity conversion, over A, requiring an array-to-pointer conversion which in turn is in the conversion category of Lvalue Transformation:

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

  • (3.2.1) S1 is a proper subsequence of S2 (comparing the conversion sequences in the canonical form defined by [over.ics.scs], excluding any Lvalue Transformation; the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence) or, if not that,
  • [...]

However, as I interpret the first emphasized segment above, Lvalue Transformation:s are excluded from both sequences S1 and S2 when applying [over.ics.rank]/3.2.1, and the second emphasized segment applies only after this exclusion has been applied.


As pointed out in a comment by @LanguageLawyer, that the rules indeed allow this ambiguity was highlighted in CWG 1789 which, afaict, have seen no progress or feedback since 2013.

1789. Array reference vs array decay in overload resolution

  • Section: 12.4.4.3 [over.ics.rank]
  • Status: drafting
  • Submitter: Faisal Vali
  • Date: 2013-10-01

The current rules make an example like

template<class T, size_t N> void foo(T (&)[N]);
template<class T> void foo(T *t);

int arr[3]{1, 2, 3};
foo(arr);

ambiguous, even though the first is an identity match and the second requires an lvalue transformation. Is this desirable?

like image 140
dfrib Avatar answered Nov 16 '22 11:11

dfrib