void func(const int &) { std::cout << "c lv ref\n"; }
void func(int &&) { std::cout << "rv ref\n"; }
func(1);
由于const lvalue引用能够接受各种数据(const和非lval,const和非rvalue),我想知道上面代码打印“rv ref”的保证是什么。它是标准化的还是编译器依赖的?
答案 0 :(得分:6)
我之前的解释是错误的 - 如T.C. mentioned in the comments,两个重载都具有相同的隐式转换序列,并且消歧是作为标准中定义的特殊打破平局发生的。
§13.3.3.1.4 [over.ics.ref],par。 1
当引用类型的参数直接将([dcl.init.ref])绑定到参数表达式时,隐式转换序列是标识转换,除非参数表达式具有type是参数类型的派生类,在这种情况下,隐式转换序列是派生到基础的转换([over.best.ics])。 [...]
如果参数类型相同,则应用于两个重载的隐式转换序列是标识转换。这还没有消除这两个功能的歧义。
消歧在这里被指定为打破平局:
§13.3.3.2 [over.ics.rank],参见3.2.3
[标准转换序列 S1是比标准转换序列S2更好的转换序列,如果 ...] S1和S2是参考绑定 ([dcl.init.ref])并且都没有引用没有ref-qualifier声明的非静态成员函数的隐式对象参数,和S1将rvalue引用绑定到rvalue并且S2绑定左值引用< / strong>即可。 [...]
引用意味着,在两个身份隐式转换序列的情况下:
将右值与右值参考绑定的序列是最佳的。
将右值与左值参考值绑定的序列比上述值更差。
[...]如果S1和S2是参考绑定[...]
需要const
将rvalues绑定到const&
的原因可以在这里找到:
§8.6.3 [dcl.init.ref],标准杆5.2
对“cv1 T1”类型的引用由“cv2 T2”类型的表达式初始化,如下所示:
[如果引用是左值引用和初始化表达式...]
否则,引用应为非易失性const类型的左值引用(即,cv1应为const),或引用应为右值引用。
如果初始化表达式 [...] 是右值(但不是位字段)或函数左值和“cv1 T1”是引用 - 与“cv2 T2”兼容