Разрешение перегрузки между ссылкой lvalue и ссылкой rvalue

#include <iostream>

using namespace std;

void func(int (&ref)[6]) { cout << "#1" << endl; }
void func(int * &&ref) { cout << "#2" << endl; }

int main()
{
  int arr[6];
  func(arr); // g++(5.4): ambiguous, clang++(3.8): #2, vc++(19.11): #1

  return 0;
}

Обе функции являются точными совпадениями. Ниже приведена цитата из стандарта:

Стандартная последовательность преобразования S1 является лучшей последовательностью преобразования, чем стандартная последовательность преобразования S2, если

...

S1 и S2 являются ссылочными привязками (8.5.3), и ни одна из них не ссылается на неявный параметр объекта объявленной нестатической функции-члена без ref-qualifier, а S1 связывает ссылку rvalue с rvalue и S2 связывает ссылку lvalue.

Не означает ли это, что второе лучше?

Обновлено:

Там есть связанный вопрос. И следующий код является упрощенной версией.

#include <iostream>

using namespace std;

void func(int *&) { cout << "#1" << endl; }
void func(int *&&) { cout << "#2" << endl; }

int main()
{
  int arr[6];
  func(arr);  // g++(5.4) and clang++(3.8): #2, vc++(19.11): ambiguous

  return 0;
}

Ответы

Ответ 1

Я думаю, это зависит от того, что означает определенная фраза.

Оба преобразования эквивалентны, потому что мы исключаем lvalue transformations (в основном массив эффективно является указателем, поэтому он не считается преобразованием), поэтому мы попадаем в следующий тай-брейк, который вы указали в [over.ics.rank]:

S1 и S2 являются привязками привязок, и ни один из них не ссылается на неявный объектный параметр нестатической функции-члена, объявленной без ref-квалификатора, а S1 связывает ссылку rvalue с rvalue и S2 связывается ссылка lvalue

Используется ли этот случай? У нас есть две привязки привязки:

int arr[6];
int (&a)[6] = arr;  // #1
int *&& b = arr;    // #2

Здесь # 1 связывает ссылку lvalue. # 2 попадает в [dcl.init.ref]:

В противном случае выражение инициализатора неявно преобразуется в prvalue типа "cv1 T1". Временное преобразование материализации применяется, и ссылка привязана к результату.

arr неявно преобразуется в prvalue типа int*, который затем привязан к b.


Итак, теперь вопрос в том, что означает ограничение в [over.ics.rank]? Это может означать:

  • ссылка rvalue, которая, как правило, связана с r значением. Это, по-видимому, толкование. Ссылка rvalue привязана к временному материализованному из преобразования prvalue arr.
  • в частности, выражение аргумента представляет собой rvalue, связанное с параметром ссылки rvalue. Это, по-видимому, gcc-интерпретация, и поскольку arr не является rvalue (это значение lvalue), этот тай-брейк пропущен и не применяются последующие тай-брейки.

Я склонен поддержать реализацию gcc здесь. В противном случае, как бы фраза "связывает ссылку rvalue с rvalue"? Ссылки Rvalue не могут связываться с lvalues. Это избыточно. Тем не менее, он неловко сформулировал эту интерпретацию.

Как есть, я назову это ошибкой формулировки.