2012-12-05 25 views
10

Perché const int è non un valore R in C++ (11)? Ho pensato che il valore R fosse "qualsiasi cosa" che non può essere sul lato sinistro e le costanti lo soddisfano. Questo codice non riesce:Costante come valore in C++ (11)

int f(int && x) { return 100; } 

void g() { 
    const int x = 1; 
    f(x); 
} 

error: invalid initialization of reference of type ‘int&&’ from expression 
of type ‘const int’ 
+2

@Kimi anche se breve il tuo commento è la risposta corretta. –

+0

Questo è vero, tuttavia vorrei ipotizzare che per coloro che non sanno quali lvalue e rvalue "siano" in C++ 11, questa risposta potrebbe essere più utile. –

+0

Non sono sicuro di come il mio commento è stato spostato qui, ma quando ho detto "questo è vero" ciò a cui mi riferivo era una risposta cancellata che affermava "Constant ha un nome quindi è un lvalue" –

risposta

12

Ok, ci sono tre categorie di espressioni :

  1. quelli che rappresentano oggetti che hanno un'identità e non possono essere spostati da;
  2. quelli che rappresentano oggetti che hanno un'identità e possono essere spostati da;
  3. quelli che rappresentano oggetti che non hanno un'identità e possono essere spostati da;

I primi sono detti lvalue, i secondi sono xvalue e i terzi sono prvali. Se mettiamo insieme lvalue e xvalue, abbiamo glvalues. Gli glalei sono tutte espressioni che rappresentano oggetti con un'identità. Se mettiamo insieme xvalue e prvalue abbiamo rvalues. I rvalues ​​sono tutte espressioni che rappresentano oggetti che possono essere spostati.

L'espressione in questione, x, è un glivalue: si può scrivere &x, quindi l'oggetto ha chiaramente un'identità.

Possiamo passare da questa espressione? Questo oggetto sta per scadere? No non lo è. Scade solo qualche tempo dopo l'espressione corrente. Ciò significa che non può essere spostato da. Questo lo rende un lvalue.

Tutti questi nomi possono essere un po 'confusi perché lvalue e rvalue in C++ non significano più ciò che intendevano nelle loro origini C. Il significato di C++ non è completamente correlato all'essere sul lato sinistro o destro dell'assegnazione .

Personalmente, preferisco usare la terminologia da this paper di Bjarne: iM-values ​​(invece di lvalue), im-values ​​(invece di xvalues), Im-values ​​(invece di prvalues), i-values ​​(invece di glvalues) e valori m (invece di rvalue). Questa non è la terminologia utilizzata dallo standard, purtroppo.


qui "hanno un'identità" significa "il suo indirizzo può essere presa"; "può essere spostato da" significa che sta per scadere, a causa della sua natura temporanea, o perché il programmatore lo ha reso esplicito nel sistema di tipi chiamando std::move o qualcosa di simile.

Si può avere rvalues ​​sul lato sinistro di assegnazione: std::vector<int>(17) = std::vector<int>(42) è un'espressione valida, anche se è inutile.

+0

Questo è un difetto, IMO e dovrebbe essere corretto, non c'è motivo di autorizzarlo. – Puppy

+0

@DeadMG: scrivi una proposta al LWG per decorare gli operatori di assegnazione del contenitore con il qualificatore di qualifica & 'ref, cioè 'Cont & operator = (Y) &;'. – Xeo

+2

@DeadMG: potrebbe interrompere il codice esistente, in modi non banali. Anche l'aggiunta di una parola chiave viene attentamente considerata e ciò causa errori di compilazione chiari. Non succederà, IOW. – MSalters

1

Il tipo di parametro è un riferimento rvalue e lo standard proibisce inizializzazione di un rvalue riferimento con un lvalue di tipo "riferimento legati".

8.5.3 References [dcl.init.ref ]

...

5 ... If T1 is reference-related to T2 and the reference is an rvalue reference, the initializer expression shall not be an lvalue.

Quindi, il seguente è un errore:

void f (long &&); 

const long x = 1; 
void g() { f (x); } 

Ma seguenti non è:

void f (long &&); 

const int x = 1; 
void g() { f (x); } 

Quindi, la ragione per l'errore non è semplicemente "l'inizializzazione non è con un rvalore", ma perché "l'inizializzazione è con un lvalue di un riferimento tipo e-related. "

0

Nelle parole semplici, si dovrebbe essere in grado di "sottrarre" il valore di rvalue. Questo è il punto centrale del diverso trattamento dei rvalues. Quindi il valore di valore dovrebbe essere senza nome-andando-a-morire-in-vicino-futuro-qualcosa.

6

I thought that R-value was 'anything' which cannot be on the left hand side [of an assignment operaton]

Questa è la definizione C++ 03 di rvalue, e anche allora il suo un colloquiale e non universalmente vero.

In C++ 11, le definizioni per lvalue e rvalue sono leggermente cambiate. Le regole sono complesse e situazioni individuali sono gestite caso per caso nello Standard, ma qui è una regola generale:

  1. Se si può prendere l'indirizzo di qualcosa, è un lvalue
  2. Se il tipo di espressione è un riferimento lvalue, questa espressione è un lvalue
  3. Se nessuno di questi casi, si tratta di un rvalue

Nel vostro caso particolare, si può prendere l'indirizzo del 012.(ad esempio, "ha un nome") ed è quindi un lvalue.

Si può leggere di più su lvalue e rvalues ​​in C++ 11 in due articoli eccellenti:

+1

Penso che tu abbia frainteso l'articolo di Scott. 'const int &&' indica sempre il riferimento di valore. Solo quando sono coinvolti i parametri del tipo di modello dedotto il significato di '&&' diventa quello di "riferimento universale" (cioè, può essere un valore o un riferimento di lvalue). –

+0

@ R.MartinhoFernandes "Leggerò l'articolo (ancora una volta, questa sarà la mia terza volta). Nel tempo libero modificherò quel bit. –

+0

Presta particolare attenzione alla regola empirica che afferma vicino l'inizio e quali parole ha sfidato. –