2012-08-08 18 views
5

C++ faq 35.16Perché la funzione membro amico non viene riconosciuta automaticamente come modello funzione?

http://www.parashift.com/c++-faq-lite/template-friends.html

#include <iostream> 

template<typename T> 
class Foo { 
public: 
    Foo(T const& value = T()); 
    friend Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs); 
    friend std::ostream& operator<< (std::ostream& o, const Foo<T>& x); 
private: 
    T value_; 
}; 

Le rivendicazioni Autor:

'L'intoppo si verifica quando il compilatore vede le linee amico fino alla definizione della classe corretta. In quel momento non sa ancora che le funzioni degli amici sono esse stesse dei modelli (perché non sono le funzioni dei membri del modello di classe come modello funzione per impostazione predefinita?); si presuppone che siano non-modelli come questo:'

Foo<int> operator+ (const Foo<int>& lhs, const Foo<int>& rhs) 
{ ... } 

std::ostream& operator<< (std::ostream& o, const Foo<int>& x) 
{ ... } 

Perché sono i non-modelli di cui sopra? non sono questi modelli che sono istanziati tramite int?

'Quando si chiama l'operatore + o operatore < < funzioni, questa ipotesi fa sì che il compilatore di generare una chiamata alle funzioni non-modello, ma il linker vi darà un errore 'non definito esterno' perché non hai mai realmente definito quelle funzioni non modello. '

Infatti, per rendere compilatore riconoscere quanto sopra come modello di funzione, il programmatore ha a che fare questo in modo esplicito come di seguito:

template<typename T> class Foo; // pre-declare the template class itself 
template<typename T> Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs); 
template<typename T> std::ostream& operator<< (std::ostream& o, const Foo<T>& x); 

Qualcuno potrebbe spiegare? Trovo questo piuttosto irritante e non so perché il compilatore non istanzia solo un'istanza di Class Foo sostituendo T con 'int' e chiamandolo un giorno.

Grazie.

risposta

5

Le funzioni membro del modello di classe fanno parte del modello e pertanto vengono create un'istanza con il modello, ma gli amici no. Si consideri il caso non-template:

struct S { 
    friend void foo(S); 
}; 

noti che void foo(S) non deve essere dichiarato, a questo punto; la dichiarazione friend sta dicendo che se una funzione void foo(S) è definita, quindi quella funzione avrà accesso a S. Potrebbe non essere mai definito, e va bene.

Con i modelli, la situazione è la stessa:

template<typename T> struct S { 
    friend void foo(S); 
}; 

Questo sta dicendo che per ogni tipo di T, se una funzione è definita void foo(S<T>) allora che la funzione ha accesso a S<T>. Tale funzione dovrebbe essere una funzione concreta, sovraccaricando:

void foo(S<char>) { } 
void foo(S<int>) { } 

Il compilatore non sa che si sta progettando in seguito per la fornitura di un modello di funzione che può essere utilizzato per tutte le T. Invece, se un modello di funzione appropriato è già dichiarato, verrà istanziato se si specifica che dovrebbe aggiungere le parentesi angolari.

Per quanto riguarda il motivo per cui è necessario inoltrare il modello, non c'è motivo per cui "il modello" debba avere una sola dichiarazione.Considerare:

#include <iostream> 
template<typename T> struct S; 
template<typename T> void foo(S<T>); 
template<typename T> void foo(S<T *>); 
template<typename T> struct S { 
    friend void foo<>(S); 
}; 
template<typename T> void foo(S<T>) { std::cout << "template template friend\n"; } 
template<typename T> void foo(S<T *>) { std::cout << "template specialization template friend\n"; } 
template void foo(S<void *>); 
int main() { 
    foo(S<int>()); 
    foo(S<void *>()); 
} 

Qui ci sono due specializzazioni di foo, e devono essere entrambi in avanti dichiarato in modo che il friend può scegliere tra di loro.

+0

Capisco un po ', ma non tutti. Con 'amico Foo operatore + (const Foo & lhs, const Foo & rhs);' avanti, cosa vedrà il compilatore? quell'operatore + sarà una funzione amico di Foo, e niente più sul tipo di ritorno, parametro funzione ecc. la dichiarazione di operatore + è trovata? – user1559625

+0

@ user1559625 il compilatore vede, per ogni particolare 'T', che l'operatore' Foo + (const Foo & lhs, const Foo & rhs); 'sarà un amico se viene definito. un modello appropriato è già dichiarato, quindi verrà istanziato Correzione – ecatmur

+0

, la sintassi è diversa per specificare un modello per l'istanziazione (le parentesi angolari aggiuntive). – ecatmur

Problemi correlati