Baccelli, camere non-Pod, rvalue e lvalues
Domanda
Qualcuno potrebbe spiegare i dettagli in termini di rvalues, lvalues, Baccelli, e non Baccelli il motivo per cui la prima espressione segnata sotto è non ok, mentre la seconda espressione segnata sotto è ok?Nella mia comprensione, sia di tipo int() e() dovrebbe essere rvalues, no?
struct A {};
int main()
{
int i;
A a;
int() = i; //Not OK (error).
A() = a; //OK.
return 0;
}
Soluzione
Rvalues sono ciò che si ottiene dalle espressioni (una semplificazione utile presi per il C standard, ma non è formulato in C++ standardese).Lvalues sono locator valori".Lvalues può essere utilizzato come rvalues.I riferimenti sono sempre lvalues, anche se const.
La differenza principale di cui è necessario essere consapevoli può essere condensato in un unico elemento:non è possibile prendere l'indirizzo di un rvalue (di nuovo, non standardese ma un utile generalizzazione delle regole).O per dirla in altro modo, non è possibile fissare una precisa posizione per un rvalue se si potesse, allora si avrebbe un lvalue.(Tuttavia, è possibile associare un const& a un rvalue per "fissarlo", e 0x sta cambiando le regole drasticamente.)
Tipi definiti dall'utente (Udt), tuttavia sono un po ' speciale:è possibile convertire qualsiasi rvalue in un lvalue, se la classe interfaccia permette di:
struct Special {
Special& get_lvalue() { return *this; }
};
void f() {
// remember "Special()" is an rvalue
Special* p = &Special().get_lvalue(); // even though you can't dereference the
// pointer (because the object is destroyed), you still just took the address
// of a temporary
// note that the get_lvalue() method doesn't need to operate on a const
// object (though that would be fine too, if the return type matched)
}
Qualcosa di simile sta avvenendo per il tuo A() = a
, se non attraverso il compilatore fornito operatore di assegnazione, per girare il rvalue A()
in *this
.Per citare standard, 12.8/10:
Se la definizione di classe non dichiara esplicitamente una copia operatore di assegnazione, si è dichiarato implicitamente.L'implicitamente dichiarato operatore di assegnazione copia di classe X avrà la forma
X& X::operator=(const X&)
E poi si va avanti con più qualifiche e specifiche, ma l'importante po ' qui.Dato che è una funzione membro, può essere chiamato a rvalues, proprio come Special: get_lvalue può essere, come se si fosse scritto A().operator=(a)
invece di A() = a
.
Il int() = 1
è esplicitamente vietato, come si è scoperto, perché ints non hanno operator= implementato nello stesso modo.Tuttavia, questo lieve discrepanza tra i tipi non importa in pratica (almeno non ho trovato).
POD significa Pianura Vecchio e di Dati è un insieme di requisiti che specificano utilizzando memcpy è equivalente a copia.Non il CONTENITORE di qualsiasi tipo per il quale non è possibile utilizzare memcpy di copia (naturale opposto del CONTENITORE, niente di nascosto da qui), che tende ad essere la maggior parte dei tipi potrai scrivere in C++.Essere POD o non-POD non cambia di cui sopra, ed è davvero un problema a parte.
Altri suggerimenti
Nella mia comprensione, sia di tipo int() e() dovrebbe essere rvalues, no?
Corretto, il epxression T()
è sempre un rvalue per scalare e tipi definiti dall'utente T
.Fintanto che non const
è coinvolto, l'espressione T()
è un modificabile rvalue, per essere più precisi.
Assegnazione coinvolgono tipi scalari richiede un modificabili lvalue sul lato sinistro dell'operatore di assegnazione.Dal int()
non è un lvalue, non è possibile assegnare a int()
.
Per i tipi definiti dall'utente, l'assegnazione è una funzione membro speciale, e le funzioni membro può anche essere chiamato rvalues (vedere §3.10 sezione 10).Ecco perché A().operator=(a)
è ben formata.
Ha C ++ fare valore di inizializzazione di un typedef POD? , che cita la standard:
L'espressione T (), dove T è un semplice-type-specificatore (7.1.5.2) per un non-array tipo di oggetto completa o la tipo void (possibilmente cv-qualificato), crea un rvalue del specificato tipo, che è di valore inizializzato
Quindi int () è un rvalue e non possono essere assegnati a, come si è visto nel primo caso.
A () non sarebbe un simlle-type-specifyer e quindi A () produce un lvalue