为什么我们不能用rvalue volatile int&&amp ;?初始化对const int的引用?

时间:2014-11-11 04:47:30

标签: 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 qualifiers
}

DEMO

但是,如果我们将int&&替换为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)选择最佳的一个,然后是   引用绑定到第一个初始化表达式lvalue   case和第二种情况下转换的左值结果   (或者,在任何一种情况下,到相应的基类子对象   宾语)。

  •   
     

[...]

     

- 否则,引用应为的左值引用   非易失性const类型(即cv1应为const)或引用   应为右值参考。

嗯,在第一个例子中,我们有一个volatile int&&类型的右值。 'otherwise'案例适用于两个例子。但5/5 [expr]说:

  

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

所以,基本上我们有一个volatile int而不是volatile int&&的右值,这意味着这两个例子都应该以相同的方式工作。

1 个答案:

答案 0 :(得分:3)

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

直接绑定失败,因为 T2 是volatile限定的而 T1 不是(在标准术语中, T1 不是参考兼容 T2 )。

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


了解为什么案例1是直接绑定。首先,此处bar() xvalue 。请参阅[basic.lval]/1“调用返回类型为右值引用的函数的结果是xvalue”。

来自[dcl.init.ref]/5

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

不适用:初始值设定项是xvalue(不是左值),它是一个引用,因此它没有类类型。

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

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

  

如果是初始化表达式

     
      
  • 是xvalue(但不是位字段),类prvalue,数组prvalue或函数lvalue,“cv1 T1”与“cv2 T2”引用兼容,或
  •   
  • [另一个案例]
  •   
     

然后引用绑定到第一种情况[...]

中的初始化表达式的值

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


NB。所有标准参考均来自C ++ 14(N3936)。由于DR1288,此部分已从C ++ 11更改。