Domanda

Credo che il T() espressione crea un rvalue (dalla norma). Tuttavia, essa compila seguente codice (almeno su gcc4.0):

class T {};

int main()
{
    T() = T();
}

So tecnicamente questo è possibile perché funzioni membro possono essere richiamate sul provvisori ed Quanto sopra è solo richiamando l'operatore = sul rvalue temporanea creata dal primo T().

Ma concettualmente questo è come assegnare un nuovo valore a un rvalue. C'è una buona ragione per cui questo è consentito?

Modifica: La ragione per cui ho trovato questo strano è che è severamente vietato il built-in tipi ancora ammessi su tipi definiti dall'utente. Ad esempio, int(2) = int(3) non sarà compilato perché questo è un "valore assegnabile non valida in assegnazione".

Quindi credo che la vera domanda è, è stato questo comportamento un po 'incoerente incorporata nel linguaggio per un motivo? O c'è per qualche ragione storica? (Per esempio sarebbe concettualmente più sana per consentire solo le funzioni membro const ad essere invocate sulle espressioni rvalue, ma questo non può essere fatto perché questo potrebbe rompere un codice già esistente.)

È stato utile?

Soluzione

Questo è il motivo per cui diverse classi nella libreria standard possono essere implementate. Si consideri ad esempio std::bitset<>::operator[]

// bit reference:
class reference {
  friend class bitset;
  reference();
public:
  ˜reference();
  reference& operator=(bool x);           // for b[i] = x;
  reference& operator=(const reference&); // for b[i] = b[j];
  bool operator˜() const; // flips the bit
  operator bool() const;  // for x = b[i];
  reference& flip();      // for b[i].flip();
};

reference operator[](size_t pos); // for b[i];

Se fai bits[i] = true esattamente assegnare un valore a una rvalue di tipo di classe. Il proxy che viene restituito dalla operator[] possono accedere i bit che sono lo spazio in modo efficiente confezionati in numeri interi.

Altri suggerimenti

Ciò è consentito solo a causa della overloading degli operatori, e la possibilità che si può sovraccaricato il operator = fare qualcosa di più di fantasia, come la stampa alla console, o bloccare un mutex, o di qualcosa di veramente.

Sì, si sta assegnando un nuovo valore a un rvalue. Più precisamente, si sta chiamando la funzione membro operator = su un rvalue. Dal momento che non si utilizza il built-in operatore di assegnamento, perché pensi che questo dovrebbe essere un problema? operator = è una funzione membro della classe, che in molti aspetti è simile a qualsiasi altra funzione membro della classe, compreso il fatto che può essere chiamato rvalues.

Si dovrebbe probabilmente anche tener conto del fatto che "essere un rvalue" è una struttura di un'espressione, non una proprietà di un oggetto. E 'vero che valuta espressione T() ad un rvalue. Tuttavia, l'oggetto temporaneo l'espressione T() produce è ancora un oggetto , che può essere letta come valore assegnabile pure. Ad esempio, qualche altra funzione membro può essere chiamata sul risultato della cessione, e vedrà il valore "nuova" (appena assegnato) dell'oggetto temporaneo attraverso *this Ivalue

(T() = T()).some_member_function();

È inoltre possibile estendere la durata della temporanea attaccando un const riferimento ad esso const T& r = T() = T(); e il valore visto attraverso r sarà il valore "nuova" dell'oggetto. Come Johannes correttamente osservato in il suo commento, questo non allegarlo a un temporaneo.

È possibile limitare operatore = al lavoro solo su lvalue a C ++ 0x:

class T
{
public:
    T& operator=(const T&) & = default;
};

Da un POV, è incoerente, ma si sta affaccia come è consistente: 1) int e altro operatore tipi predefiniti ancora si comportano come fanno in C, 2) = on class-tipi si comporta come qualsiasi altro metodo fa senza bisogno di ancora un altro caso particolare.

compatibilità

C è stato molto apprezzato fin dall'inizio del C ++ e C ++ probabilmente non sarebbe qui oggi senza di essa. In modo che una parte è generalmente una buona cosa.

Il secondo punto è sottovalutato. Non speciale operatore involucro = consente il codice senza senso di "lavorare", ma perché abbiamo a cuore il codice senza senso, in primo luogo? Garbage in, garbage out. Le norme attuali conferiscono un senso definito (UB qui sarebbe male), con costi trascurabili, per quanto io abbia mai visto.

Data la mia druthers, le cose sarebbero essere semplificata ulteriormente, in modo int() = int() sarebbe stato permesso. C ++ 0x inizia a testa in quella direzione con rvalue riferimenti, prvalues, ecc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top