2016-02-15 11 views
10

Secondo msvc, gcc e clang, il seguente codice è illegale:Utilizzando un modello di classe in un modello di funzione con il parametro di riferimento universale

template <typename T> 
void f(T&& e) { 
    std::vector<T> v; 
    // do something with v and e ... 
} 
int main() { 

    int i; 
    f(i); 
} 

rendimenti MSVC

xmemory0 (591): errore C2528: "puntatore": puntatore al riferimento è illegale

gcc e clang danno messaggi di errore simili. Si noti che il parametro di riferimento universale e non viene utilizzato. Il compilatore non riesce, ovviamente, creare un'istanza il vettore v, lamentano di essere utilizzato con un riferimento a int:

nota: vedi riferimento al modello di classe di un'istanza 'std::vector<T,std::allocator<_Ty>>' essere compilato con

[ 
     T=int &, 
     _Ty=int & 
    ] 

Ma non riesco a vedere dove viene istanziato il modello di funzione f con un riferimento a int.

Qualcuno può spiegare gli errori del compilatore che vediamo qui?

+5

Si noti che * il riferimento di inoltro * è ora il termine preferito. – TartanLlama

risposta

18

Quando f viene chiamato con un lvalue int, T saranno dedurre come int&, così v sarà un std::vector<int&>. Questo non è valido

Un modo per aggirare il problema è quello di rimuovere i riferimenti da T prima di utilizzarlo:

template <typename T> 
void f(T&& e) { 
    using value_type = typename std::remove_reference<T>::type; 
    //using value_type = std::remove_reference_t<T>; for C++14 
    std::vector<value_type> v; 
    // do something with v and e ... 
} 

Tuttavia, se si desidera che la funzione di essere il più generico possibile, si dovrebbe usare std::decay invece di std::remove_reference. Ciò consentirà a f di funzionare con tipi, matrici e funzioni qualificati per CV.

+2

Anche se 'C++ 11' è taggato, forse suggerisce anche' remove_reference_t' per ogni evenienza? Lo rende un buon one-liner. –

+0

@YamMarcovic Grazie, l'ho aggiunto, anche se preferirei farlo su due righe piuttosto che una. – TartanLlama

+0

Una nota per i lettori: mi piacerebbe sottolineare che poiché f è un modello di funzione anche la T in std :: vector diventa T e quando f è istanziata con un lvalue, secondo le regole citate dalle risposte. Prima, la mia comprensione era che la T in std :: vector non può essere diversa dalla T in . –

7

Scott Meyers spiega in questo article.

Se l'espressione inizializzare un riferimento universale è un lvalue, il riferimento universale diventa un riferimento Ivalue.

Se l'espressione inizializzazione del riferimento universale è un valore rvalue, il riferimento universale diventa un riferimento di rvalue.

Nel tuo caso i è un lvalue e così T si deduce come int&.