2015-01-09 9 views
12

Ich weiß, dass es bereits ähnliche Themen gibt (z. B. this).Da ein String-Literal als Lvalue gilt, warum muss der Binding-Lvalue-Bezug const sein?

Das Beispiel in diesem Thema gegeben war:

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

ist klar, dass std :: string() ist ein R-Wert. Aber meine Frage ist, warum ist S1 legal, während S2 nicht ist?

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

Der Standard stellt klar, dass Stringliterale lvalues ​​sind (die, da sie hinter den Kulissen technisch const char sind verständlich ist *). Wenn ich kompilieren obwohl s2, erhalte ich folgendes:

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"; 

Ich verstehe, dass die Standard-Definition von lvalues ​​und rvalues ​​gegenseitig ausschließen, so ist dies möglicherweise ein Fehler mit dem Compiler? Ich verwende gcc 4.9.2 in diesem Beispiel. Wäre dies auch einer der Fälle, in denen das Literal wirklich ein xvalue ist?

+0

Da nicht-konstante Lvalue-Referenzen nicht an Provisorien binden können. Const Lvalues ​​Referenzen können. Ein temporäres Objekt vom Typ string wird aus "const char *" erstellt. Dies ist an die Referenz gebunden. – bolov

+0

Sind Sie sicher, dass Ihr Beispielcode das ist, was Sie kompiliert haben? 'const std :: string & s2 =" String literal "' ist absolut gültig, während 'std :: string & s1 =" String literal "' nicht zutrifft. – mbgda

+0

Editiert es. Danke für die schnelle Antwort. Ich habe gerade realisiert, dass ich falsch kopiert habe. – elau

Antwort

19

Das Problem ist, dass ein Zeichenfolgenliteral nicht vom Typ std::string oder Unterklasse davon ist - es ist vom Typ
char const[N]. Somit ist der Typ des Initialisierers nicht referenzkompatibel mit dem Zieltyp der Referenz, und ein temporäres muss erstellt und an die Referenz gebunden werden.

Provisorien können jedoch nicht an nicht konstante Lvalue-Referenzen gebunden werden. I.e. Ihr Fall entspricht

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

das ist, auch nach Ihnen, eindeutig schlecht gebildet.


Eigentlich der genaue Grund dies nicht der Fall nicht funktioniert, weil Provisorien können nicht auf nicht-const lvalue Referenzen gebunden sein, sondern vielmehr, dass die Initialisierung einer nicht konstanten lvalue Referenz unterliegt bestimmte Anforderungen, die char const[N] kann nicht erfüllen in diesem Fall [dcl.init.ref]/5:

Ein Verweis auf den Typ „CV1T1“ durch einen Ausdruck von Typs initialisiert „CV2T2“ wie folgt: 012.

  • Wenn die Referenz ein L-Wert als Hinweis und der Initialisierer Ausdruck

    • ist ein L-Wert (aber kein Bit-Feld), und „CV1T1“ reference-kompatibel "cv2T2" oder
    • hat einen Klassentyp (d. H, T2 ist ein Klasse-Typ), wobei T1 und T2 nicht Referenz bezogenen und implizit zu einem L-Wert umgewandelt werden kann vom Typ „CV3 T3“, wobei „CV1T1“ Referenz-kompatibel mit „CV3 istT3“ wird (diese Umwandlung wird durch Aufzählen der anwendbaren Umwandlungsfunktionen (13.3.1.6), und die Auswahl der besten, durch eine Überlast Auflösung (13.3) ausgewählt)

    dann die Referenz gebunden der Initialisierungsausdruck lvalue in der erste Fall und das Lvalue-Ergebnis der Umwandlung in dem zweiten Fall (oder in jedem Fall zu der entsprechenden Basisklasse Unterobjekt des Objekts).

  • Andernfalls wird die Referenz eine L-Wert Bezugnahme auf einen nichtflüchtigen const Typen sein (d.h. CV1 soll const sein), oder die Referenz wird ein R-Wert Bezug.

    • [..]

106) Dies erfordert eine Konvertierungsfunktion (12.3.2) einen Referenztyp zurückkehrt.

10

Das Zeichenfolgenliteral kann ein Lvalue sein, ist aber kein string Objekt. Es wird ein temporäres string erstellt, das ein rvalue ist.

+1

Um dies darzulegen, nutzt 's1' die Regel, dass das Binden eines const-Verweises auf ein temporäres die Lebensdauer des temporären auf den Gültigkeitsbereich des Verweises verlängert, während das Binden eines nichtkonstanten Verweises auf ein temporäres ein Fehler ist. – tmyklebu

1

Zuerst wird ein String ist ein const char * oder const char [N] kein std::string. Sie ordnen also diese char * Strings nicht direkt zu. std::string hat einen Konstruktor, der eine const char [N] nimmt und der Compiler verwendet sie automatisch, um eine neue Instanz zu konstruieren.

Aber wenn Sie const für s2 verwenden, haben Sie es gerade dem Compiler unmöglich gemacht, die neue std::string Instanz zu s2 zuzuweisen.

Also ich glaube, Sie haben den Unterschied zwischen einem "String" des Typs const char [N] und einem "String" des Typs std::string falsch verstanden. Der Standard bezieht sich auf const char [N], wenn es sich um Zeichenfolgen handelt, die ein Lvalue sind, aber Sie versuchen, dies auf eine std::string anzuwenden, für die die Regel des Standards nicht gilt.

+1

Zunächst ist ein String-Literal ein 'const char [N]', kein 'char *'. –

+0

Danke, aber war der Sarkasmus wirklich nötig? – erapert