左值参考和右值参考之间的重载分辨率

oli*_*ist 16 c++ overloading rvalue-reference language-lawyer

#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;
}
Run Code Online (Sandbox Code Playgroud)

这两个函数都是完全匹配.以下是标准的引用:

标准转换序列S1是比标准转换序列S2更好的转换序列

...

S1和S2是引用绑定(8.5.3),并且都不引用没有ref-qualifier声明的非静态成员函数的隐式对象参数,S1将rvalue引用绑定到rvalue,S2绑定左值引用.

这不是意味着第二个更好吗?

更新:

一个相关的问题.以下代码是它的简化版本.

#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;
}
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 3

我认为这取决于特定短语的含义。

\n\n

这两种转换是等效的,因为我们排除了左值转换(基本上,数组实际上是一个指针,因此它不算作转换),因此我们进入了您在[over.ics.rank]中指出的下一个决胜局:

\n\n
\n

S1 和 S2 是引用绑定,两者都没有引用未使用 ref 限定符声明的非静态成员函数的隐式对象参数,并且 S1 将右值引用绑定到右值,S2 绑定左值引用

\n
\n\n

这个案例适用吗?我们确实有两个引用绑定:

\n\n
int arr[6];\nint (&a)[6] = arr;  // #1\nint *&& b = arr;    // #2\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里,#1 绑定了一个左值引用。#2 属于[dcl.init.ref]

\n\n
\n

否则,初始化表达式将隐式转换为 \xe2\x80\x9ccv1 T1\xe2\x80\x9d 类型的纯右值。应用临时具体化转换并将引用绑定到结果。

\n
\n\n

arr隐式转换为 类型的纯右值int*,然后绑定到b

\n\n
\n\n

所以现在的问题是 - [over.ics.rank] 中的限制意味着什么?这可能意味着:

\n\n
    \n
  • 通常绑定到右值的右值引用。这显然是clang的解释。右值引用绑定到从 的纯右值转换中具体化的临时值arr
  • \n
  • 具体来说,参数表达式是绑定到右值引用参数的右值。这显然是 gcc 的解释,因为arr不是右值(它是左值),因此会跳过此决胜局,并且不会应用后续的决胜局。
  • \n
\n\n

我倾向于支持 gcc 的实现。否则,“将右值引用绑定到右值”这句话的意义是什么?右值引用不能绑定到左值。这是多余的。也就是说,对于这种解释来说,它的措辞也很尴尬。

\n\n

事实上,我将其称为措辞错误。

\n