【问题标题】:Why can't we initialize a reference to const int with an rvalue volatile int&&?为什么我们不能用右值 volatile int&& 初始化对 const int 的引用?
【发布时间】:2014-11-11 04:47:30
【问题描述】:

我写了下面的例子:

#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

但如果我们将int&amp;&amp; 替换为int,它就可以正常工作:

#include <iostream>

volatile int bar()
{
    return 1;
}

int main()
{
    const int& i = bar(); //OK

}

DEMO

这并不完全清楚。标准所说的是 (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&amp;&amp; 类型的右值。 'otherwise' 案例适用于这两个示例。但是5/5 [expr] 说:

如果一个表达式最初的类型是“对 T 的引用”(8.3.2, 8.5.3),在进一步分析之前将类型调整为 T

所以,本质上我们有一个volatile int 类型的右值而不是volatile int&amp;&amp;,这意味着这两个示例应该以相同的方式工作。

【问题讨论】:

    标签: c++ reference


    【解决方案1】:

    这两种情况的区别在于,在情况1中,引用直接绑定,而在情况2中,它不直接绑定(即引用绑定到一个临时的;定义可以在[dcl.init.ref]的最后一段)。

    直接绑定失败,因为 T2 是 volatile-qualified 而 T1 不是(在标准术语中,T1 不是 reference-compatibleT2)。

    间接绑定成功是因为从bar() 返回的引用初始化临时int 时,临时不是volatile。 (临时的类型为 cv1 T1)。


    看看为什么案例 1 是直接绑定。首先,bar() 在这里是一个 xvalue。参见[basic.lval]/1“调用返回类型为右值引用的函数的结果是一个xvalue”。

    来自[dcl.init.ref]/5

    • 如果引用是左值引用并且初始化表达式[是左值]或[具有类类型]

    不适用:初始化器是一个 xvalue(不是左值),它是一个引用,所以它没有类类型。

    • 否则,引用应为对非易失性 const 类型的左值引用(即 cv1 应为 const),或者引用应为右值引用

    这确实适用:const int &amp; 是对非易失性 const 类型的左值引用。顺着这棵树下去:

    如果初始化表达式

    • 是一个 xvalue(但不是位域)、类纯右值、数组纯右值或函数左值,并且“cv1 T1”与“cv2 T2”引用兼容,或者
    • [另一种情况]

    那么在第一种情况下,引用将绑定到初始化表达式的值 [...]

    这确实适用,因为 bar() 是一个 xvalue。所以引用绑定到 xvalue,这被称为 直接绑定,因为它没有绑定到临时值。


    注意。所有标准参考都来自 C++14 (N3936) 。由于 DR1288,本节从 C++11 更改。

    【讨论】:

    • 另外,如果我没记错的话,在这种情况下返回的右值将是一个悬空引用,因为创建引用的 temp 在赋值后立即被销毁 i = bar();为什么不直接按值返回,让编译器优化(省略)或使用移动构造函数?
    • @victor 我相信他正在编写自己的编译器,因此需要了解所有这些奇怪的情况
    • 在你的第二个例子中, bar() 是一个prvalue;在第一个示例中,它是一个 xvalue。 不太清楚。你如何区分这些?
    • @DmitryFucintv bar() 是一个 xvalue,如果 bar 是一个返回右值引用的函数。见 [basic.lval]/1
    • 我明白了。谢谢你。您能否提供一个引用 decibes xvalues 直接绑定到左值引用; prvalues 没有。?
    猜你喜欢
    • 2021-02-20
    • 1970-01-01
    • 2010-11-30
    • 2022-01-08
    • 2013-09-14
    • 1970-01-01
    • 2020-05-30
    • 1970-01-01
    • 2021-03-19
    相关资源
    最近更新 更多