函数重载的优先级(引用)

4
void func(const int &) { std::cout << "c lv ref\n"; }
void func(int &&) { std::cout << "rv ref\n"; }

func(1);

由于const左值引用能够接受各种类型的数据(const和非左值,const和非右值),我想知道上述代码输出“rv ref”的保证是什么。这是标准化的还是编译器相关的?

1个回答

7

我的先前解释是错误的 - 正如 T.C.在评论中提到的,两个重载函数拥有相同的隐式转换序列,而消歧是根据标准定义的特殊选项来进行的。


§13.3.3.1.4 [over.ics.ref], 第1段

当引用类型的参数直接绑定到一个参数表达式时,除非参数表达式的类型是参数类型的派生类,否则隐式转换序列为标识转换([dcl.init.ref]),在这种情况下,隐式转换序列为派生到基类转换([over.best.ics])。[...]

如果参数类型相同,则应用于两个重载函数的隐式转换序列为标识转换。这仍然不能消除两个函数之间的歧义。

这里指定了一种消除歧义的方法:

§13.3.3.2 [over.ics.rank], par 3.2.3

[如果标准转换序列S1优于标准转换序列S2,则] S1和S2都是引用绑定([dcl.init.ref])且没有引用非静态成员函数声明的隐式对象参数,S1绑定到右值引用并且S2绑定到左值引用。[...]

引用的两个隐式转换序列相同时:

  • 将右值绑定到右值引用的序列是最佳的。

  • 将右值绑定到左值引用的序列比上述序列差。


如果S1和S2是引用绑定,则需要使用const将rvalue绑定到const&中,原因可以在此处找到:§8.6.3[dcl.init.ref], par 5.2。一个类型为“cv1 T1”的引用通过一个类型为“cv2 T2”的表达式进行初始化,方法如下:如果引用是左值引用并且初始化表达式...否则,引用应该是非易失性const类型的左值引用(即,cv1应该是const),或者引用应该是右值引用。如果初始化表达式是rvalue(但不是位域)或函数lvalue,并且“cv1 T1”与“cv2 T2”兼容,则...

不,那不是它的工作方式。在这两种情况下都有一个ICS(如果无法形成ICS,则该函数不可行),并且两者都是身份转换。这由over.ics.rank/3.2.3中的决胜者控制。 - T.C.
@T.C. 我没能理解这个标准。对于传播错误信息我感到抱歉 - 我已经编辑了问题,希望现在是正确的。 - Vittorio Romeo
@Criss:您可能需要再次查看答案,因为之前的答案是错误的 - 抱歉。 - Vittorio Romeo
1
好的,感谢VittorioRomeo对您的纠正。还要感谢@T.C.的敏锐 :) - Criss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接