2012-03-17 11 views
14

Questa domanda deriva dai problemi sollevati da this answer.Ramificazione degli operatori di assegnazione con valori anziché riferimenti

Normalmente, definiamo gli operatori di assegnazione copia per il tipo T come T& operator=(const T&) e spostiamo gli operatori di assegnazione per il tipo T come T& operator=(T&&).

Tuttavia, cosa succede quando utilizziamo un parametro di valore anziché un riferimento?

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

Questo dovrebbe rendere T sia copia che spostamento assegnabile. Tuttavia, quello che voglio sapere è quali sono le implicazioni linguistiche per T?

In particolare:

  1. fa questo conteggio come una copia operatore di assegnazione per T, secondo le specifiche?
  2. Conta come operatore di assegnazione di spostamento per T, in base alle specifiche?
  3. T ha un operatore di assegnazione copie generato dal compilatore?
  4. T ha un operatore di assegnazione del movimento generato dal compilatore?
  5. In che modo influisce sulle classi di tratti come std::is_move_assignable?
+0

Discussione correlata: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value – mavam

+0

Ottengo errori del compilatore sia su Visual Studio che su g ++ se ho qualcosa sia T che operatore = (T t) e T & operator = (T && t) poiché è ambiguo – user929404

+0

@ user929404: E tu dovresti. Il punto è che tu sostituisci * entrambi * la copia e sposta l'incarico con la sola assegnazione di valore. –

risposta

14

La maggior parte di questo è descritto in §12.8. Paragrafo 17 definisce ciò che conta come operatori di assegnamento copia dall'utente dichiarato:

Una copia assegnazione di controllo d'uso dichiarata X::operator= è una funzione non statico membro non-modello di classe X con esattamente un parametro di tipo X, X&, const X&, volatile X& o const volatile X&.

Paragrafo 19 definisce ciò che conta come si muovono gli operatori di assegnazione dall'utente dichiarato:

Una mossa assegnazione di controllo d'uso dichiarata X::operator= è una funzione non statico membro non template di classe X con esattamente un parametro di tipo X&&, const X&&, volatile X&& o const volatile X&&.

Quindi, conta come un operatore di assegnazione copia, ma non come operatore di assegnazione spostamento.

Paragrafo 18 dice quando il compilatore genera copia operatori di assegnazione:

Se la definizione della classe non dichiara esplicitamente una copia assegnazione operatore, si è dichiarato in modo implicito. Se la definizione della classe dichiara un costruttore di movimento o un operatore di assegnazione di spostamento, l'operatore di assegnazione copia dichiarato dichiarato viene cancellato; altrimenti, è definito come predefinito (8.4).Il secondo caso è deprecato se la classe ha un costruttore di copia dichiarato dall'utente o un distruttore dichiarato dall'utente.

Paragrafo 20 ci dice quando il compilatore genera spostare operatori di assegnazione:

Se la definizione di una classe X non dichiara esplicitamente una mossa operatore di assegnazione, uno sarà implicitamente dichiarato come default se e solo se
[...]
- x non ha un operatore di assegnamento per copia user-dichiarato,
[...]

Poiché la classe dispone di un operatore di assegnazione copia dichiarato dall'utente, nessuno di quelli impliciti verrà generato dal compilatore.

std::is_copy_assignable e std::is_move_assignable sono descritti nella Tabella 49 come aventi lo stesso valore, rispettivamente is_assignable<T&,T const&>::value e is_assignable<T&,T&&>::value. Tale tabella ci dice che is_assignable<T,U>::value è true quando:

L'espressione declval<T>() = declval<U>() è ben formata se trattati come operando non valutata (punto 5). Il controllo dell'accesso viene eseguito come se in un contesto non correlato a T e U. Viene considerata solo la validità del contesto immediato dell'espressione di assegnazione.

Dato che sia declval<T&>() = declval<T const&>() e declval<T&>() = declval<T&&>() sono ben formate per quella classe, conta comunque come copia assegnabile e spostare assegnabile.

Come accennato nei commenti, ciò che è curioso di tutto questo è che, in presenza di un costruttore movimento, che si operator= eseguire correttamente mosse, ma tecnicamente non conta come operatore di assegnazione mossa. È ancora più strano se la classe non ha un costruttore di copie: avrà un operatore di assegnazione copia che non fa copie, ma solo mosse.

Problemi correlati