2015-01-09 18 views
12

So che ci sono argomenti simili a questo già (come this).Poiché un valore letterale stringa è considerato un valore lvalue, perché il riferimento lvalue di associazione deve essere const?

L'esempio riportato in questo argomento è stato questo:

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

Chiaramente, che std :: string() è un rvalue. Tuttavia, la mia domanda è perché è legale s1 mentre s2 non è?

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

La norma afferma chiaramente che le stringhe letterali sono lvalue (che è comprensibile dal momento che sono tecnicamente const char * dietro le quinte). Quando compilo S2, però, ottengo il seguente:

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

Capisco che la definizione standard di lvalue e rvalues ​​si escludono a vicenda, in modo da questo potenzialmente un errore con il compilatore? Sto usando gcc 4.9.2 in questo esempio. Questo sarebbe anche uno dei casi in cui il letterale è davvero un valore x?

+0

Poiché i riferimenti non costanti non possono essere associati ai provvisori. i riferimenti di const lvalues ​​possono. Un oggetto temporaneo di tipo string viene creato da "const char *". Questo è legato al riferimento. – bolov

+0

Sei sicuro che il tuo codice di esempio è quello che hai compilato? 'const std :: string & s2 =" String literal "' è totalmente valido, mentre, ovviamente 'std :: string & s1 =" String letteral "' non lo è. – mbgda

+0

Modificato. Grazie per la risposta rapida. Mi sono appena accorto di aver copiato/incollato male. – elau

risposta

19

Il problema è che una stringa letterale non è di tipo std::string o sottoclasse di esso - è di tipo
char const[N]. Pertanto, il tipo di inizializzatore non è un riferimento compatibile con il tipo di destinazione del riferimento e deve essere creato e associato al riferimento.

Tuttavia, i temporari non possono essere associati a riferimenti non costanti. Cioè il tuo caso è equivalente a

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

che è, anche secondo te, chiaramente mal formata.


realtà la ragione precisa non funziona non è perché i provvisori possono essere associati a riferimenti non const Ivalue, ma piuttosto che l'inizializzatore di un riferimento Ivalue non const è soggetto a determinati requisiti che char const[N] non può incontrano in questo caso, [dcl.init.ref]/5:

un riferimento a tipo “CV1T1” viene inizializzato da un'espressione di tipo “cv2T2” come segue: 012.

  • Se il riferimento è un riferimento Ivalue e l'espressione inizializzatore

    • è un lvalue (ma non è un campo di bit), e “CV1T1” è riferimento compatibile con "cv2T2" o
    • ha un tipo di classe (es., T2 è un tipo di classe), dove T1 non è riferimento correlati a T2, e può essere convertito in modo implicito un Ivalue di tipo “CV3 T3,” dove “CV1T1” è riferimento compatibile con “CV3T3” (questa conversione è selezionata per l'enumerazione delle funzioni di conversione applicabili (13.3.1.6) e scegliere la migliore attraverso sovraccarico risoluzione (13.3)),

    allora il riferimento è destinata a l'espressione di inizializzazione lvalue in il primo caso e il risultato lvalue della conversione nel secondo caso (o, in entrambi i casi, nell'appropriato oggetto base dell'oggetto dell'oggetto).

  • caso contrario, il riferimento è un riferimento ad un valore assegnabile tipo const non volatile (cioè CV1 è const), o il riferimento deve essere un riferimento rvalue.

    • [..]

106) Questo richiede una funzione di conversione (12.3.2) restituendo un tipo di riferimento.

10

La stringa letterale può essere un lvalue, ma non è un oggetto string. È stato creato uno string temporaneo che è un valore rvalue.

+1

Per esporre su questo, 's1' sfrutta la regola che legare un riferimento const a un temporaneo estende la durata del temporaneo allo scope del riferimento, mentre legare un riferimento non const a un temporaneo è un errore. – tmyklebu

1

In primo luogo, una stringa è un const char * o const char [N] non un std::string. Quindi non stai assegnando direttamente quelle stringhe char *. std::string ha un costruttore che prende uno const char [N] e il compilatore lo utilizza automaticamente per costruire una nuova istanza.

Ma quando si utilizza const per s2 si è appena reso impossibile per il compilatore assegnare la nuova istanza std::string a s2.

Quindi, alla fine, penso che tu abbia frainteso la differenza tra una "stringa" di tipo const char [N] e una "stringa" di tipo std::string. Lo standard si riferisce a const char [N] quando si parla di stringhe come lvalue, ma si sta tentando di applicarle a std::string a cui la regola dello standard non si applica.

+1

In primo luogo, una stringa letterale è un 'const char [N]', non un 'char *'. –

+0

Grazie, ma il sarcasmo era davvero necessario? – erapert

Problemi correlati