【问题标题】:Since a string literal is considered an lvalue, why must the binding lvalue reference be const?既然字符串文字被认为是左值,为什么绑定左值引用必须是 const?
【发布时间】:2015-03-08 07:32:55
【问题描述】:

我知道已经有类似的主题(例如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 的情况之一吗?

【问题讨论】:

  • 因为非常量左值引用不能绑定到临时对象。 const lvalues 引用即可。字符串类型的临时对象是从“const char*”创建的。这与引用绑定。
  • 你确定你的示例代码是你编译的吗? const std::string &amp; s2 = "String literal" 完全有效,而 std::string &amp; s1 = "String literal" 显然不是。
  • 已编辑。感谢您的快速回复。我刚刚意识到我复制/粘贴错误。
  • “字符串文字”是语言语法中的词素,而不是对象。词位表示的对象是一个字符数组,而不是 std::string 类型的对象(它来自库,完全不同)。
  • @KerrekSB 这似乎含糊不清。该标准规定“尝试修改字符串文字的效果是未定义的。”,这意味着在某些上下文中字符串文字字符数组。

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


【解决方案1】:

问题是字符串文字不是std::string 类型或其子类——它是
char const[N] 类型。 因此初始化器的类型与引用的目标类型不兼容,必须创建一个临时对象并将其绑定到该引用。

但是,临时对象不能绑定到非 const 左值引用。 IE。你的情况相当于

std::string& s = std::string("Abcdefg");

即使根据您的说法,这显然是不正确的。


实际上它不起作用的确切原因不是因为临时对象不能绑定到非常量左值引用,而是非常量左值引用的初始化程序受制于char const[N] 无法满足的某些要求本例,[dcl.init.ref]/5:

对类型“cv1T1”的引用由以下表达式初始化 输入“cv2T2”如下:

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

    • 是一个左值(但不是位域),并且“cv1 T1”与“cv2 T2”或
    • 具有类类型(即 T2 是类类型),其中 T1 与 T2 没有引用相关,并且可以隐式转换为左值 类型为“cv3 T3”,其中“cv1 T1”与引用兼容 “cv3T3106(这个转换是通过枚举适用的 转换函数 (13.3.1.6) 并通过 重载决议 (13.3)),

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

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

    • [..]

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

【讨论】:

    【解决方案2】:

    字符串字面量可能是左值,但不是string 对象。正在创建一个临时的string,它是一个右值。

    【讨论】:

    • 为了解释这一点,s1 利用了将 const 引用绑定到临时对象的规则,将临时对象的生命周期扩展到引用的范围,同时将非 const 引用绑定到临时是一个错误。
    【解决方案3】:

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

    但是当为 s2 使用 const 时,编译器无法将新的 std::string 实例分配给 s2。

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

    【讨论】:

    • 首先,字符串文字是const char[N],而不是char*
    • 谢谢,但讽刺真的有必要吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多