2010-10-28 36 views
37

J'ai une classe de base semblable au code ci-dessous. Je tente de surcharger < < à utiliser avec cout. Cependant, g ++ est dit:déclaration d'ami déclare une fonction non-modèle

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 

J'ai essayé d'ajouter <> après < < dans la déclaration de classe/prototype. Cependant, je l'obtiens does not match any template declaration. J'ai essayé de faire en sorte que la définition de l'opérateur soit entièrement modélisée (ce que je veux), mais j'ai seulement réussi à l'utiliser avec le code suivant, avec l'opérateur instancié manuellement.

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

Je veux avoir tout cela ou similaire dans l'en-tête, 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; 
} 

J'ai lire ailleurs en ligne que mettre <> entre < < et() dans le prototype devrait répare ça, mais ce n'est pas le cas. Est-ce que je peux obtenir ceci dans un modèle simple de fonction?

+4

C'est exactement le problème résolu par Dan Saks' [expression de "faire de nouveaux amis"] (http://en.wikibooks.org/wiki/More_C % 2B% 2B_Idioms/Making_New_Friends). _ (Désolé pour le commentaire en retard.) _ –

Répondre

29

On dirait que vous voulez changer:

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

Pour:

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

Donc, je ne vous croyais pas, mais cela fonctionne. Cependant, je ne peux pas utiliser 'T' parce qu'il' ombrage' le 'T 'déjà existant du modèle de classe. –

+1

Est-ce que GCC vous avertit de l'ombrage? –

+5

Oui, GCC a donné un avertissement à propos de l'observation. J'ai remplacé T par Y et cela l'a résolu. 'error: ombres template parm 'classe T'' –

-3

changement

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

à

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

Cela ne fonctionnera certainement pas. En plus de donner 'employee.cpp: 32: erreur: 'T' n'a pas été déclaré dans cette portée', même après en avoir fait un modèle dans un fichier .h ou .cpp, cela ne fonctionnera pas en raison de symboles indéfinis lors de la liaison. En plus, j'ai toujours l'avertissement. Je veux que ce soit comme un modèle normal défini dans un fichier d'en-tête. –

+0

J'ai complètement raté la classe en cours de base à ce moment-là. Devrait juste être T, mais je vois des réponses plus complètes, donc je vais les modifier. –

15

Gcc vous avertit à juste titre. Malgré ses apparences (il prend l'argument Base), ce n'est pas un modèle de fonction.

Votre définition de classe comporte une déclaration sans modèle de la fonction friend (sans le modèle), mais la définition de la fonction friend ultérieurement est un modèle de fonction (c'est-à-dire commence par template ..).

Aussi votre opérateur < < prend une Base *. Ce n'est pas correct. Il devrait être la base const & pour le conserver est intégré dans la sémantique

Probablement que vous cherchez quelque chose comme ci-dessous:

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

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

Si vous voulez entièrement basé sur un modèle, c'est probablement ce que vous voulez. Mais je ne suis pas sûr à quel point c'est utile par rapport à la précédente. Puisque la recherche implique ADL, vous ne serez jamais capable de résoudre une condition où T n'est pas égal à U (tant que l'appel provient d'un contexte non lié à cette classe, par ex.de la fonction « principale »)

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

Eh bien, l'utilisation de l'opérateur '<< ne trouverait jamais d'instanciation avec' U! = T'. Un appel direct potentiellement pourrait cependant, ce qui serait juste vraiment bizarre. Cela ne serait important que si 'operator <<' pour Base 'accédait à une variable globale de type' Base '. –

+0

@Ben Voigt: Ajout de la partie 'tant que l'appel provient d'un contexte non lié à cette classe, par ex. de la fonction 'principale'. J'espère que c'est plus clair maintenant – Chubsdad

+0

Peut-être ajouter comment définir la fonction ami en dehors de la définition de la classe, par souci d'exhaustivité? – Gauthier

10

probablement ce que vous cherchez est:

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

Ce amis une seule instanciation du modèle, celui où le paramètre de modèle de l'opérateur correspond au paramètre de modèle de la classe .

MISE À JOUR: Malheureusement, c'est illégal. MSVC et Comeau le rejettent tous deux. Ce qui soulève la question de savoir pourquoi le message d'erreur original suggéré à peu près EXACTEMENT cette approche.

+6

La [FAQ C++] (http://www.parashift.com/c++-faq-lite/templates.html#faq-35.16) indique que la ligne 'friend' dans la déclaration de classe doit avoir' <> ', pas un ''. –

+2

Et apparemment, vous n'êtes pas censé avoir besoin de la ligne 'template <>' avant cela. (Pas d'accès au compilateur en ce moment, ne l'ai pas essayé.) –

4

changer

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

à

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

devrait fonctionner aussi bien - je viens de résoudre un problème identique de cette façon.

0

changer

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

Pour

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