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

Since a string literal is considered an lvalue, why must the binding lvalue reference be const?

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

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

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

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

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

即使在您看来,这也显然是错误的。


实际上它不起作用的确切原因不是因为临时对象不能绑定到非常量左值引用,而是因为非常量左值引用的初始化程序需要满足某些要求 char const[N]在这种情况下不能满足,[dcl.init.ref]/5:

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:

  • If the reference is an lvalue reference and the initializer expression

    • is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2” or
    • has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be implicitly converted to an lvalue of type “cv3 T3,” where “cv1 T1” is reference-compatible with “cv3 T3106(this conversion is selected by enumerating the applicable conversion functions (13.3.1.6) and choosing the best one through overload resolution (13.3)),

    then the reference is bound to the initializer expression lvalue in the first case and to the lvalue result of the conversion in the second case (or, in either case, to the appropriate base class subobject of the object).

  • Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference.

    • [..]

106) This requires a conversion function (12.3.2) returning a reference type.

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

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

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