由于字符串文字被认为是左值,为什么绑定左值引用必须是const?

时间:2015-01-09 21:41:49

标签: c++ reference language-lawyer string-literals lvalue

我知道有些主题与此类似(例如this)。

本主题中给出的示例如下:

std::string & rs1 = std::string();

显然,std :: string()是一个右值。但是,我的问题是为什么s1是合法的而s2不是?

const std::string& s1 = "String literal";
std::string& s2 = "String literal";

标准明确指出字符串文字是左值(这是可以理解的,因为它们在技术上是const char *幕后)。当我编译s2时,我得到以下内容:

prog.cpp:4:19: error: invalid initialization of non-const reference of type
'std::string& {aka std::basic_string<char>&}' from an rvalue of type
'const char*' std::string& s2 = "String literal";

据我所知,左值和右值的标准定义是互斥的,所以这可能是编译器的错误吗?我在这个例子中使用gcc 4.9.2。这也是文字实际上是xvalue的情况之一吗?

3 个答案:

答案 0 :(得分:20)

问题是字符串文字不是std::string类型或其子类 - 它的类型为char const[N]。 因此,初始值设定项的类型与引用的目标类型不是引用兼容的,并且必须创建临时值并将其绑定到引用。

但是,临时值不​​能绑定到非常量左值引用。即你的情况相当于

std::string& s = std::string("Abcdefg");
即使根据你的说法,这显然是不正确的。


实际上,它不起作用的确切原因并不是因为临时值不能绑定到非常量左值引用,而是非常量左值引用的初始化符合{{1}的某些要求在这种情况下无法满足,[dcl.init.ref] / 5:

  

对类型“ cv1 char const[N]”的引用由表达式初始化   输入“ cv2 T1”如下:

     
      
  • 如果引用是左值引用和初始化表达式

         
        
    • 是左值(但不是位字段),“ cv1 T2”与“ cv2 {{1}”引用兼容}“或
    •   
    • 具有类类型(即,T2是类类型),其中T1与T2不是引用相关的,并且可以隐式转换为左值   类型为“cv3 T3”,其中“ cv1 T1”与参考兼容   “ cv3 T2 106 (通过枚举适用情况选择此转换   转换函数(13.3.1.6)并选择最佳的一个   重载决议(13.3)),
    •   
         

    然后将引用绑定到初始化表达式lvalue中   第一种情况和转化的左值结果   第二种情况(或者,在任何一种情况下,到适当的基类   对象的子对象)。

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

         
        
    • [..]
    •   
  •   
     
     

106)这需要转换函数(12.3.2)返回引用类型。

答案 1 :(得分:10)

字符串文字可以是左值,但它不是string对象。正在创建临时string,这是一个右值。

答案 2 :(得分:2)

首先,字符串是const char *const char [N]而不是std::string。所以你不是直接分配那些char *字符串。 std::string有一个构造函数,它接受const char [N],编译器自动使用它构造一个新实例。

但是当对{s}使用const时,你只是让编译器无法将新的std::string实例分配给s2。

所以最后我认为你误解了const char [N]类型的“字符串”和类型std::string的“字符串”之间的区别。标准是指const char [N],当它谈论字符串是左值时,你试图将其应用于标准规则不适用的std::string