2015-05-20 14 views
13

Sto cercando di capire i riferimenti rvalue. Ho visto come vengono utilizzati nei costruttori, con le cose come std::move e std::forward, ma io ancora non capisco perché questo non funziona:C++, riferimenti di rvalue nei parametri di funzione

void func(string&& str) 
{ 
    cout << str << endl; 
} 
int main(int argc, char* argv[]) 
{ 
    string s("string"); 
    func(s); 
} 

E questo lo fa:

template<typename T> 
void func(T&& str) 
{ 
    cout << str << endl; 
} 
int main(int argc, char* argv[]) 
{ 
    string s("string"); 
    func(s); 
} 

Perché funziona con la versione del modello di funzione?

+4

L'ultima versione funziona perché "T" viene dedotto come 'stringa &'."Quando il tipo di parametro della funzione è del formato T &&, dove T è un parametro del modello e l'argomento della funzione è un lvalue di tipo A, il tipo A viene utilizzato per la deduzione degli argomenti del modello." Usa 'std :: move' se vuoi che il primo funzioni. –

+0

Questo è un caso speciale di deduzione di template, qui (e solo qui AFAIK), 'T' può essere dedotto a un tipo di riferimento. Normalmente nella deduzione del tipo di modello "T" è dedotta solo come non riferimento. –

+1

possibile duplicato di [Sintassi per riferimenti universali] (http://stackoverflow.com/questions/14302849/syntax-for-universal-references) –

risposta

14

Come @Peter Detto questo, il tipo di T si deduce come string&, e la regola di riferimento-collasso C++ s 'dice:

T & & ⇒ T & // dal C++ 98
T & & & ⇒ T & // nuovo per C++ 0x
T & & & ⇒ T & // nuovo per C++ 0x
T & & & & ⇒ T & & // nuovo per C++ 0x

Così func s’esemplificazione è in realtà:

void func(string& str) 

E funziona.

6

Qualche spiegazione formale oltre a @ di songyuanyao risposta:

N4296::14.8.2.1 [temp.deduct.call]:

Template detrazione argomento viene fatto confrontando ogni funzione tipo di parametro template (lo chiamano P) con il tipo del corrispondente argomento della chiamata (chiamarlo A) come descritto di seguito.

N4296::14.8.2.1/3 [temp.deduct.call]:

Un riferimento inoltro è un riferimento rvalue ad un parametro di modello cv-qualificato. Se P è un riferimento di inoltro e l'argomento è un lvalue, il tipo "lvalue riferimento a A" viene utilizzato al posto di A per la deduzione del tipo.

La norma stabilisce inoltre il seguente esempio:

template <class T> int f(T&& heisenreference); 
template <class T> int g(const T&&); 
int i; 
int n1 = f(i); // calls f<int&>(int&) 
int n2 = f(0); // calls f<int>(int&&) 
int n3 = g(i); // error: would call g<int>(const int&&) 

questo è esattamente il vostro caso.