2010-10-28 10 views
37

Ich habe eine Basisklasse, die dem folgenden Code ähnlich ist. Ich versuche, < < zu überladen, um mit cout zu verwenden. jedoch g ++ sagt:Friend-Deklaration deklariert eine Nicht-Template-Funktion

base.h:24: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, Base<T>*)’ declares a non-template function 
base.h:24: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning 

Ich habe versucht, das Hinzufügen <> nach < < in der Klassendeklaration/Prototyp. Aber dann bekomme ich es does not match any template declaration. Ich habe versucht, die Operatordefinition vollständig templated (was ich will), aber ich konnte es nur mit dem folgenden Code arbeiten, mit dem Operator manuell instanziiert.

base.h

template <typename T> 
class Base { 
    public: 
    friend ostream& operator << (ostream &out, Base<T> *e); 
}; 

base.cpp

ostream& operator<< (ostream &out, Base<int> *e) { 
    out << e->data; 
return out; 
} 

Ich möchte nur diese oder ähnliche haben im Header, base.h:

template <typename T> 
class Base { 
    public: 
    friend ostream& operator << (ostream &out, Base<T> *e); 
}; 

template <typename T> 
ostream& operator<< (ostream &out, Base<T> *e) { 
    out << e->data; 
return out; 
} 

Ich habe Lesen Sie an anderer Stelle online, dass <> zwischen < < und() im Prototyp sollte behebe das, aber das tut es nicht. Kann ich das in eine einzelne Funktionsvorlage bekommen?

+4

Das ist genau das Problem von Dan Saks' gelöst [ "Neue Freunde" Idiom] (http://en.wikibooks.org/wiki/More_C % 2B% 2B_Idioms/Making_New_Friends). _ (Sorry für den späten Kommentar.) _ –

Antwort

29

Es klingt wie Sie ändern möchten:

friend ostream& operator << (ostream& out, const Base<T>& e); 

An:

template<class T> 
friend ostream& operator << (ostream& out, const Base<T>& e); 
+17

Also ich habe dir nicht geglaubt, aber das funktioniert. Allerdings kann ich 'T' nicht verwenden, da es das bereits vorhandene' T' der Klassenvorlage "schattiert". –

+1

Gibt GCC Ihnen eine Warnung über die Abschattung? –

+5

Ja, GCC warnte vor Abschattung. Ich habe T durch Y ersetzt und das hat es gelöst. 'Fehler: Schatten Vorlage Parm 'Klasse T'' –

-3

Änderung

ostream& operator<< (ostream &out, Base<int> *e) { 
    out << e->data; 
    return out; 
} 

zu

ostream& operator<< (ostream &out, T *e) { 
    out << e->data; 
    return out; 
} 
+0

Dies wird definitiv nicht funktionieren. Neben der Angabe von 'employee.cpp: 32: error: 'T' wurde in diesem Bereich nicht deklariert', funktioniert es auch nach dem Erstellen einer Vorlage in einer .h- oder .cpp-Datei aufgrund nicht definierter Symbole während der Verknüpfung nicht. Außerdem bekomme ich immer noch die Warnung. Ich möchte, dass es wie eine normale Vorlage ist, die in einer Header-Datei definiert ist. –

+0

Ich habe die Klasse zu diesem Zeitpunkt komplett verpasst. Sollte nur T sein, aber ich sehe vollständigere Antworten, also werde ich sie aufrüsten. –

15

GCC warnt Sie zu Recht. Trotz seiner Erscheinung (es braucht das Argument Base) ist es keine Funktionsvorlage.

Ihre Klassendefinition hat eine Nicht-Template-Deklaration der Friend-Funktion (ohne die Vorlage), aber die Freundesfunktionsdefinition ist später eine Funktionsvorlage (d. H. Beginnt mit der Vorlage ..).

Auch Ihr Operator < < benötigt eine Base *. Das ist nicht richtig. Es sollte Basis konst & sein seiner eingebauten in Semantik

Sie den Blick auf etwas zu behalten Wahrscheinlich wie folgt:

template <typename T> 
class Base { 
    public: 
    friend ostream& operator << (ostream &out, Base<T> const &e){ 
     return out; 
    }; 
}; 

int main(){ 
    Base<int> b; 
    cout << b; 
} 

Wenn Sie voll auf Vorlagen wollen, dann ist dies wahrscheinlich das, was Sie wollen. Aber ich bin mir nicht sicher, wie viel nützlicher das ist als das vorhergehende. Da die Suche ADL beinhaltet, werden Sie nie in der Lage sein, irgendeine Bedingung zu lösen, bei der T nicht gleich U ist (solange der Anruf von einem Kontext kommt, der nicht mit dieser Klasse verwandt ist, z.von ‚main‘ Funktion)

template <typename T> 
class Base { 
    public: 
    template<class U> friend ostream& operator << (ostream &out, Base<U> const &e){ 
     return out; 
    }; 
}; 

int main(){ 
    Base<int> b; 
    cout << b; 
} 
+0

Nun, die Verwendung des Operators '<<' würde niemals eine Instanzierung mit 'U! = T' finden. Ein direkter Anruf könnte aber möglicherweise, was nur wirklich komisch wäre. Es wäre nur wichtig, ob der Operator << 'für 'Base ' auf eine globale Variable vom Typ 'Base ' zugreifen würde. –

+0

@Ben Voigt: Hinzufügen des Teils 'so lange der Anruf aus einem Kontext stammt, der nicht mit dieser Klasse in Verbindung steht, z. von 'Hauptfunktion'. Hoffe, es ist jetzt klarer – Chubsdad

+0

Vielleicht hinzufügen, wie die Friend-Funktion außerhalb der Klassendefinition, für die Vollständigkeit zu definieren? – Gauthier

10

Wahrscheinlich für das, was Sie suchen ist:

template <typename T> 
class Base; 

template <typename T> 
ostream& operator<< (ostream &, const Base<T>&); 

template <typename T> 
class Base 
{ 
    public: 
    template<> 
    friend ostream& operator << <T>(ostream &, const Base<T> &); 
}; 

template <typename T> 
ostream& operator<< (ostream &out, const Base<T>& e) 
{ 
    return out << e->data; 
} 

nur eine einzige Instanziierung der Vorlage Diese Freunde, die, wo der Template-Parameter der Klasse der Template-Parameter übereinstimmt Bediener .

UPDATE: Leider ist es illegal. Sowohl MSVC als auch Comeau lehnen es ab. Das wirft die Frage auf, warum die ursprüngliche Fehlermeldung GENAU diesen Ansatz nahe legte.

+6

Die [C++ FAQ] (http://www.parashift.com/c++faq-lite/templates.html#faq-35.16) sagt, dass die 'Freund'-Zeile in der Klassendeklaration ein' <> 'haben sollte, nicht ein ''. –

+2

Und anscheinend sollten Sie die 'template <>' Zeile davor nicht brauchen. (Kein Zugriff auf Compiler im Moment, habe es nicht versucht.) –

4

Wechsel

friend ostream& operator << (ostream& out, const Base<T>& e); 

zu

friend ostream& operator << <T>(ostream& out, const Base<T>& e); 

sollte auch funktionieren - ich ein identisches Problem auf diese Weise nur gelöst.

0

Ändern

friend ostream& operator << (ostream &out, Base<T> *e)` 

Um

template<T> friend ostream& operator << (ostream &out, Base *e) 
Verwandte Themen