2011-11-29 3 views
5

_Remove_reference esiste per, come sapete, la conversione di T & a T o T & & a T.Perché std :: move() non funziona senza _Remove_reference?

ho fatto il seguente codice in un umore allegro, non funziona affatto come mi aspettavo, ma non hanno idea perché

template<class _Ty> 
struct _Remove_reference 
{ // remove reference 
    typedef _Ty _Type; 
    static void func(){ cout << "1" << endl; } 
}; 

// template<class _Ty> 
// struct _Remove_reference<_Ty&> 
// { // remove reference 
// typedef _Ty _Type; 
// static void func(){ cout << "2" << endl; } 
// }; 
// 
// template<class _Ty> 
// struct _Remove_reference<_Ty&&> 
// { // remove rvalue reference 
// typedef _Ty _Type; 
// static void func(){ cout << "3" << endl; } 
// }; 

template<class _Ty> inline 
    typename _Remove_reference<_Ty>::_Type&& 
    move(_Ty&& _Arg) 
{ // forward _Arg as movable 
    typename _Remove_reference<_Ty>::func(); 
    return ((typename _Remove_reference<_Ty>::_Type&&)_Arg); 
} 

int main(){ 
    int a1= 3; 
    int&& a2 = move(a1); // can't convert the a1 to int&& 
    return 0; 
} 

Suppongo che si tratti di regole di compressione di riferimento e deduzione argomento modello ma sono confuso. la mia curiosità su questo deve essere infranta per me per dormire stretto.

Grazie in anticipo.

risposta

8

Dato

template<class _Ty> inline 
typename _Remove_reference<_Ty>::_Type&& 
move(_Ty&& _Arg) 

Quando si esegue move(a1), _Ty si deduce come int&. _Ty&& sarebbe quindi ancora int& a causa delle regole di compressione di riferimento, quindi è necessario rimuovere il riferimento per ottenere int prima di poterlo fare un riferimento di rvalue.

Questo è un caso speciale delle regole di deduzione degli argomenti del modello. Se hai un argomento di funzione che è T&& dove T è un parametro di modello, se si passa un lvalue (ovvero un oggetto con nome o un riferimento di lvalue) alla funzione, allora T viene dedotto come X& dove X è il tipo dell'oggetto lvalue . Se si passa un valore di rvalue (un riferimento temporaneo o di un valore) alla funzione, allora T viene dedotto come X.

ad es. move(a1) deduce _Ty per essere int&, mentre move(42) deduce _Ty per essere int.

BTW: Immagino che tu abbia preso questo codice dalla libreria standard del tuo compilatore --- nomi decorati con un trattino basso principale e una lettera maiuscola _Come _Questi sono riservati al compilatore e all'implementazione della libreria standard.

+0

Grazie. Lo apprezzo. Ma chiedendosi perché ho bisogno di annullare l'annotazione del codice? Se lo scopo di _remove_reference è convertirli in T, perché ho bisogno di questi versetti di specializzazione del modello? –

+1

Le specializzazioni sono il modo in cui '_Remove_reference' funziona. Il modello principale corrisponde a qualsiasi cosa e restituisce lo stesso tipo, quindi '_Remove_reference :: type' è solo' int'. Le specializzazioni parziali per i riferimenti fanno la rimozione di riferimento. '_Remove_reference ' corrisponde alla prima specializzazione parziale, quindi viene utilizzato al posto del modello principale. ** All'interno di questa specializzazione **, '_Ty' è solo' int' (quindi '_Ty &' è 'int &'), quindi '_Remove_reference :: type' è un typedef per' int'. –

+1

Per il collasso di riferimento, consultare http://thbecker.net/articles/rvalue_references/section_08.html. L'intero articolo, infatti, da pagina 1, è una buona lettura. Leggi dall'inizio per ottenere il contesto delle cose. – wilhelmtell