C++ 为什么可以';t我们用右值volatile int初始化对const int的引用&&;?
我编写了以下示例:C++ 为什么可以';t我们用右值volatile int初始化对const int的引用&&;?,c++,reference,C++,Reference,我编写了以下示例: #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 qua
#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
}
这还不清楚。标准所说的是(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)选择最佳,然后 引用绑定到第一个表达式中的初始值设定项表达式左值 第二种情况下转换的左值结果 (或者,在任何一种情况下,都是到 对象)
volatile int&
的右值。而“否则”
情况适用于这两个示例。但是5/5[expr]
说:
如果表达式最初的类型为“引用T”(8.3.2,
8.5.3),在进一步分析之前,将类型调整为T
因此,本质上,我们有一个类型为
volatile int
的右值,而不是volatile int&
,这意味着这两个示例将以相同的方式工作。两种情况之间的区别是,在情况1中,引用直接绑定,而在情况2中,它不直接绑定(即,引用绑定到临时;定义可在[dcl.init.ref]
的最后一段中找到)
直接绑定失败,因为T2是volatile限定的,而T1不是(在标准术语中,T1与T2不兼容)
间接绑定成功,因为当从bar()
返回的引用初始化临时int
时,临时的volatile
(临时的类型为cv1 T1)
要了解为什么案例1是直接绑定。首先,
bar()
在这里是一个xvalue。请参见[basic.lval]/1
“调用返回类型为右值引用的函数的结果是一个xvalue”
从[dcl.init.ref]/5
:
- 如果引用是左值引用且初始值设定项表达式[是左值]或[具有类类型]
- 否则,该引用应为对非易失常数类型的左值引用(即,cv1应为常数),或该引用应为右值引用
const int&
是对非易失性const类型的左值引用。沿着此树:
如果初始值设定项表达式
- 是xvalue(但不是位字段)、类prvalue、数组prvalue或函数左值,且“cv1 T1”是与“cv2 T2”兼容的引用,或
- [另一个案例]
bar()
是一个xvalue。因此,引用被绑定到xvalue,这称为直接绑定,因为它没有绑定到临时值
注意:所有标准引用都来自C++14(N3936)。由于DR1288,本节从C++11更改为。此外,如果我没有弄错的话,在这种情况下返回的右值将是悬空引用,因为创建引用的温度在赋值i=bar()后立即被销毁;为什么不直接按值返回并让编译器优化(省略)或使用移动构造函数?@victor我相信他正在编写自己的编译器,因此需要理解第二个示例中的所有奇怪情况,bar()是一个prvalue;在第一个示例中,它是一个xvalue。不太清楚。如何区分它们?@DmitryFucintv
bar()
是一个xvalue,如果bar
是一个返回右值引用的函数。请参见[basic.lval]/1我知道了。谢谢。你能提供一个引用描述吗?xvalues直接绑定到左值引用;prvalues没有。?
#include <iostream>
volatile int bar()
{
return 1;
}
int main()
{
const int& i = bar(); //OK
}