2013-10-03 16 views
18

Diciamo che ho questa funzione:Comportamento della funzione template C++

bool f(int&& one, int&& two) { } 

Se tento di chiamare con questo codice:

int x = 4; 
f(x, 5); 

il compilatore si lamenta che non può convertire x da lvalue riferimento al riferimento di rvalue, che è corretto.

Ora, se converto f in una funzione di modello come questo:

template <class T, class U> 
bool f(T&& one, U&& two) { } 

poi mi può chiamare con un riferimento lvalue:

int x = 5; 
f(x, 5); 

Perché è così? Perché il compilatore non si lamenta in questo caso?

risposta

8

Perché c'è un argomento detrazione modello, crollando di riferimento succede. È ciò che Scott Meyers chiama riferimenti universali. Lo U&& diventerà effettivamente int &. C'è un bel article and video su come funziona e come potrebbe essere usato.

6

Questo accade a causa di collasso norme di riferimento aggiunti in C++ 11

A& & becomes A& 
A& && becomes A& 
A&& & becomes A& 
A&& && becomes A&& 

Nei modelli di queste regole vengono applicate, ma non in una funzione normale non v'è alcun riferimento collasso normalmente in funzione. Esistono altre situazioni specifiche in cui si verificherà il collasso di riferimento come in presenza di auto, decltype o typedef (che include le dichiarazioni using) che spiega i risultati della compilation. Il collasso di riferimento doveva essere aggiunto in C++ 11 perché altrimenti l'utilizzo di riferimenti come A & & diventerebbe un errore poiché non è possibile avere un riferimento a un riferimento.

+2

Mentre il collasso di riferimento si verifica nel caso di un "riferimento universale", la vera magia avviene prima di questo passaggio e si verifica durante la deduzione degli argomenti del modello. La tua nota sul crollo dei riferimenti che non funziona in una funzione normale è semplicemente sbagliata; il collasso di riferimento può avvenire ovunque: 'usando T = int &&; void foo (T & x); 'qui x è un 'int &' a causa di un collasso di riferimento. – Simple

+0

@Simple sembra proprio giusto, sapevo già che decltypes e auto potevano avere un riferimento al collasso, non sapevo che un typedef poteva causarlo, io Modificherò la mia risposta – aaronman

10

Per § 8.3.3/6. È la regola di collasso di riferimento.

template <class T> void func(T&&) // Accepts rvalue or lvalue 
void func(T&&)      // Accepts rvalue only 
void func(T&)      // Accepts lvalue only 

Worth esempio dal progetto di norma:

int i; 
typedef int& LRI; 
typedef int&& RRI; 

LRI& r1 = i;   // r1 has the type int& 
const LRI& r2 = i;  // r2 has the type int& 
const LRI&& r3 = i; // r3 has the type int& 

RRI& r4 = i;   // r4 has the type int& 
RRI&& r5 = 5;   // r5 has the type int&& 

decltype(r2)& r6 = i; // r6 has the type int& 
decltype(r2)&& r7 = i; // r7 has the type int& 
+3

Questo è il tipo di contro-intuitivo ... –

+0

@VioletGiraffe benvenuto nel mondo di C++ –

+0

@jk .: E lì pensavo di capire la maggior parte di questo mondo! –