2012-08-08 4 views
5

C++ FAQ 35,16Warum wird die Funktion friend member nicht automatisch als Funktionsvorlage erkannt?

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_; 
}; 

Der Autor behauptet:

‚Der Haken passiert, wenn der Compiler die eigentliche Freund Linien Weg nach oben in der Klassendefinition sieht. In diesem Moment ist es noch nicht bekannt, die Freunde Funktionen sind selbst Vorlagen (Warum ist es? Sind nicht Klassenvorlage Mitglied Funktionen Funktion Vorlage standardmäßig sein?); nimmt sie nicht-Vorlagen wie diese sind:‘

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

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

Warum sind die oben genannten nicht-Vorlagen? sind das nicht diese Vorlagen, die über int instanziiert werden?

‚Wenn Sie die Operator + oder Betreiber < < Funktionen aufrufen, diese Annahme veranlasst den Compiler einen Aufruf an die Nicht-Template-Funktionen zu erzeugen, aber der Linker geben Ihnen einen‚undefinierten extern‘Fehler, weil Sie eigentlich nie definiert diese Nicht-Template-Funktionen. '

In der Tat zu machen Compiler die oben als Funktionsschablone erkennen, Programmierer hat dies wie unten explizit zu tun:

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); 

Könnte jemand erklären? Ich finde das ziemlich ärgerlich und weiß nicht, warum der Compiler nicht nur eine Instanz der Klasse Foo instanziiert, indem er T durch 'int' ersetzt, und es einen Tag nennt.

Danke.

Antwort

5

Klassenvorlagenelementfunktionen sind Teil der Vorlage und werden daher mit der Vorlage instanziiert, Freunde jedoch nicht. Betrachten wir die Nicht-Template-Fall:

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

Beachten Sie, dass void foo(S) an dieser Stelle nicht erklärt werden muss; Die friend Deklaration besagt, dass , wenn eine Funktion void foo(S) definiert ist, dann diese Funktion Zugriff auf S haben wird. Es könnte nie wirklich definiert werden, und das ist in Ordnung.

Mit Vorlagen ist die Situation die gleiche:

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

Dies sagt, dass für jede Art T, , wenn eine Funktion void foo(S<T>) definiert ist dann die Funktion Zugriff auf S<T> hat. Diese Funktion wird erwartet, dass eine konkrete Funktion zu sein, durch Überlastung:

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

Der Compiler weiß nicht, dass Sie später planen eine Funktionsvorlage zu liefern, die für alle T verwendet werden kann. Wenn eine geeignete Funktionsvorlage bereits deklariert ist, wird sie instanziiert, wenn Sie angeben, dass dies durch Hinzufügen von spitzen Klammern erfolgen soll.

Warum Sie die Vorlage weiterleiten müssen, gibt es keinen Grund, dass "die Vorlage" nur eine Deklaration haben muss.Bedenken Sie:

#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 *>()); 
} 

Hier gibt es zwei Spezialisierungen von foo, und sie müssen beide nach vorne, so erklärt werden, dass die friend zwischen ihnen auswählen können.

+0

Ich verstehe einige, aber nicht alle. Mit 'Freund Foo Operator + (const Foo & lhs, const Foo & rhs);' entlang, was wird Compiler sehen? dieser Operator + wird eine Freund-Funktion von Foo sein, und nichts mehr auf Rückgabetyp, Funktionsparameter usw., bis ein Vorwärts Erklärung des Operators + gefunden? – user1559625

+0

@ user1559625 der Compiler sieht, für eine bestimmte 'T', dass' Foo Operator + (const Foo & lhs, const Foo & rhs); 'wird ein Freund, wenn es definiert ist. Darüber hinaus, wenn eine geeignete Vorlage ist bereits deklariert, dann wird sie instanziiert – ecatmur

+0

Korrektur: Die Syntax ist anders, um eine Vorlage für die Instanziierung anzugeben (die zusätzlichen spitzen Klammern). – ecatmur

Verwandte Themen