我写了下面的例子:
#include <iostream>
volatile int&& bar()
{
return 1;
}
int main()
{
const int& i = bar(); //error: binding of reference to type 'const int'
//to a value of type 'volatile int' drops qualifiers
}
DEMO http://coliru.stacked-crooked.com/a/b54a5c0f73a3f559
但如果我们更换int&&
with int
它工作正常:
#include <iostream>
volatile int bar()
{
return 1;
}
int main()
{
const int& i = bar(); //OK
}
DEMO http://coliru.stacked-crooked.com/a/87b7778545007a7e
这还不太清楚。标准所说的是(8.5.3/5 [dcl.init.ref]
):
对类型“cv1 T1”的引用由类型的表达式初始化
“cv2 T2”如下:
— 如果引用是左值引用并且
初始化表达式
是左值(但不是位字段),并且“cv1 T1”与“cv2 T2”引用兼容,或者
具有类类型(即 T2 是类类型),其中 T1 与 T2 没有引用相关,
并且可以转换为“cv3 T3”类型的左值,其中“cv1 T1”与引用兼容
“cv3 T3”108(通过枚举适用的转换函数来选择此转换
(13.3.1.6) 并通过重载决策选择最好的一个 (13.3)),然后
引用绑定到第一个中的初始化表达式左值
情况和第二种情况下转换的左值结果
(或者,在任何一种情况下,到适当的基类子对象
目的)。
[...]
— 否则,该引用应为对 a 的左值引用
非易失性 const 类型(即 cv1 应为 const),或引用
应为右值引用。
好吧,在第一个示例中,我们有一个类型的右值volatile int&&
。还有'otherwise'
case 适用于这两个示例。但5/5 [expr]
says:
如果表达式最初具有“对 T 的引用”类型(8.3.2,
8.5.3),在任何进一步分析之前将类型调整为 T
所以,本质上我们有一个类型的右值volatile int
代替volatile int&&
,这意味着这两个示例应以相同的方式工作。
两种情况的区别在于,在情况1中,参考文献直接绑定在情况 2 中,它不直接绑定(即引用绑定到临时的;定义可以在最后一段中找到)[dcl.init.ref]
).
直接绑定失败的原因是T2是 volatile 限定的并且T1不是(在标准术语中,T1 is not 参考兼容 with T2).
间接绑定成功是因为当临时int
从返回的引用初始化bar()
,暂时不是volatile
。 (临时有类型cv1 T1).
看看为什么案例 1 是直接绑定。首先,bar()
is an xvalue这里。看[basic.lval]/1
“调用返回类型为右值引用的函数的结果是 xvalue”。
From [dcl.init.ref]/5
:
- 如果引用是左值引用并且初始化表达式 [是左值] 或 [具有类类型]
不适用:初始化器是一个xvalue(不是lvalue),并且它是一个引用,因此它没有类类型。
- 否则,该引用应为非易失性 const 类型的左值引用(即 cv1 应为 const),或者该引用应为右值引用
这确实适用:const int &
是对非易失性 const 类型的左值引用。下这棵树:
如果初始化表达式
- 是 xvalue(但不是位域)、类纯右值、数组纯右值或函数左值,并且“cv1 T1”与“cv2 T2”引用兼容,或者
- [另一个案例]
那么在第一种情况下,引用将绑定到初始化表达式的值 [...]
这确实适用,因为bar()
是一个 x 值。因此引用绑定到 x 值,这称为直接绑定因为它不是临时绑定的。
注意。所有标准参考均来自 C++14 (N3936)。由于 DR1288,本节从 C++11 进行了更改。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)