2015-01-09 4 views
12

Я знаю, что есть темы, похожие на это уже (например, this).Поскольку строковый литерал считается lvalue, почему ссылка привязки lvalue будет const?

Пример, приведенный в этой теме был такой:

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

Очевидно, что станд :: строка() является Rvalue. Однако мой вопрос в том, почему s1 является законным, а s2 - нет?

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

Стандарт четко гласит, что строковые литералы являются lvalues ​​(что вполне понятно, так как они являются технически Const символ * за кадром). Когда я компилирую 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"; 

Я понимаю, что стандартное определение lvalues ​​и rvalues ​​являются взаимоисключающими, так это потенциально ошибка с компилятором? Я использую gcc 4.9.2 в этом примере. Будет ли это также одним из случаев, когда букваль действительно является значением xvalue?

+0

Поскольку ссылки не константы lvalue не могут привязываться к временным. const lvalues ​​ссылки могут. Временной объект типа string создается из «const char *». Это связано с ссылкой. – bolov

+0

Вы уверены, что ваш пример кода - это то, что вы скомпилировали? 'const std :: string & s2 =" String literal "' является полностью допустимым, тогда как, очевидно, 'std :: string & s1 =" String literal "' is not. – mbgda

+0

Отредактировано. Спасибо за быстрый ответ. Я просто понял, что я скопировал/вставил неправильно. – elau

ответ

19

Проблема заключается в том, что строковый литерал не имеет типа std::string или его подкласса - он имеет тип
char const[N]. Таким образом, тип инициализатора не является ссылочным, совместимым с целевым типом ссылки, и необходимо создать временное и привязать к ссылке.

Однако временные рамки не могут быть связаны с неконстантными ссылками на значения. То есть ваш случай эквивалентен

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

который, даже в соответствии с вами, явно плохо сформирован.


На самом деле точная причина не работает не потому, что временные конструкции не могут быть связаны с неконстантная Lvalue ссылок, а то, что инициализатор неконстантного ссылки Lvalue подчиняется определенным требованиям, которые char const[N] не может встречаются в этом случае, [dcl.init.ref]/5:

ссылка на тип «CV1T1» инициализируется выражением типа «CV2T2» следующим образом:

  • Если ссылка является именующей ссылкой и выражение инициализатора

    • является именующим (но не битовым поле), и «CV1T1» является ссылкой совместит с "cv2T2" или
    • имеет тип класса (т.е., Т2 тип класса), где T1 не ссылаться на связанные с Т2, и может быть неявно преобразован в именующее типа «CV3 Т3», где «CV1T1» является ссылкой совместим с «CV3T3» (это преобразование выбираются путем перечисления применимой функции преобразования (13.3.1.6) и выбора лучших вариантов через перегрузки разрешения (13,3)),

    то ссылку обязательно выражение инициализатора lvalue в первый случай и результат lvalue преобразования в двоичном случае (или, в любом случае, в соответствующий базовый класс подобъекта объекта).

  • В противном случае, ссылка должна быть именующей ссылкой на энергонезависимый тип сопзЬ (т.е. CV1 должен быть константным), или ссылка должна быть ссылкой Rvalue.

    • [..]

106) Это требует функции преобразования (12.3.2) возвращает ссылку типа.

10

Строковый литерал может быть lvalue, но это не объект string. Существует временное создание string, которое является rvalue.

+1

Чтобы изложить это, 's1' использует правило, связывающее ссылку const со временным, продлевает время жизни временного объекта в области ссылки, тогда как привязка неконстантной ссылки на временную является ошибкой. – tmyklebu

1

Во-первых, строка является const char * или const char [N] не std::string. Таким образом, вы не напрямую назначаете эти строки char *. std::string имеет конструктор, который принимает const char [N], и компилятор автоматически использует его для создания нового экземпляра.

Но при использовании const для s2 вы просто не смогли компилятору назначить новый экземпляр std::string на s2.

Так что, в конце концов, я думаю, вы неправильно поняли разницу между «строкой» типа const char [N] и «строкой» типа std::string. Стандарт ссылается на const char [N], когда речь идет о значениях строк, но вы пытаетесь применить их к std::string, к которым правило стандарта не применяется.

+1

Во-первых, строковый литерал является 'const char [N]', а не 'char *'. –

+0

Спасибо, но был ли сарказм действительно нужен? – erapert