2010-11-09 22 views
4

Comment est-ce que je peux surcharger l'opérateur d'insertion (< <) et/ou d'extraction (>>) dans une classe de modèle SANS le faire en ligne. Je voudrais avoir l'opérateur < ou >> en tant que classe d'ami. Je sais comment faire inline exemple de ligne dans une classe de matriceclasse de modèles et extraction d'insertion surchargés

friend ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix) 
{ 
    ... 
    // create the ostr 
    return ostr; 
} 

mais je voudrais avoir le code en dehors de la définition de templateclass. Après le nom de la fonction, je l'ai fait mais quand j'ai essayé d'installer une matrice de type SOMETYPE, il m'a donné une erreur qu'il ne savait pas comment extraire ou insérer pour ce type.

+1

Vous devriez lire http://www.parashift.com/c++-faq-lite /templates.html#faq-35.16. BTW, comme un modèle amusant ction sera implicitement en ligne de toute façon. – UncleBens

+0

La prochaine fois, veuillez utiliser le bouton '101010' au sommet du volet d'édition pour mettre en forme le code dans votre message. Ceci, et beaucoup plus est expliqué sur la fenêtre flottante "Comment éditer" sur la droite du volet d'édition. – sbi

Répondre

1

Si vous voulez vraiment définir l'opérateur à l'extérieur et se lier d'amitié que l'instanciation de l'opérateur qui coïncide dans le type avec ce modèle instanciation, la syntaxe correcte est:

template <typename T> class test; // forward declare template class 
template <typename T>    // forward declare the templated operator 
std::ostream& operator<<(std::ostream&, test<T> const &); 

template <typename T> 
class test {      // define the template 
    friend std::ostream& operator<< <T>(std::ostream&, test<T> const &); // befriend 
}; 
template <typename T>    // define the operator 
std::ostream& operator<<(std::ostream& o, test<T> const &) { 
    return o; 
} 

Dans la plupart des cas, il ne vaut pas les tracas de Tirez la définition hors de la classe, sachant que vous devez toujours le fournir dans un en-tête et le travail supplémentaire requis.

Notez également qu'il existe de légères différences pour le compilateur en ce qui concerne la recherche. Dans le cas où la fonction est inline dans la définition de la classe, le compilateur ne trouvera pas cette fonction sauf si l'un des arguments est réellement du type du template, donc il réduit efficacement la visibilité et la quantité de travail que le compilateur doit faire (si le modèle operator<< est défini en dehors de la classe, le compilateur le trouvera comme candidat pour la résolution de surcharge dans tous les endroits où il trouve a << b, seulement pour le rejeter dans tous les cas où le second argument n'est pas test<T> (et il montrera l'opérateur basé sur le modèle en tant que candidat dans tous les messages d'erreur où il ne peut pas correspondre operator<<, qui est déjà une liste assez longue.)

+0

pouvez-vous s'il vous plaît expliquer pourquoi on devrait déclarer à l'avance l'opérateur sur le modèle? –

+0

@Silverrocker: La raison principale est que le langage a été conçu en pensant à un compilateur à un seul passage (\ *). Le problème est que l'instruction 'friend' indique au compilateur: * accorder l'accès à cette instanciation particulière du template *. Pour que cela ait du sens pour le compilateur, le template doit déjà avoir été déclaré. Il est similaire à: 'void foo() {bar (5); } modèle barre vide (T) {} '. Vous ne pouvez pas utiliser ou faire référence à une spécialisation ou une instanciation d'un modèle de classe avant que le modèle générique et les spécialisations ne soient déclarés. –

+0

(*) Ceci est un but, pas une réalité, tous les compilateurs doivent parcourir le fichier d'entrée plus d'une fois pour d'autres raisons. Quelque part, j'ai lu que celui qui a effectué moins de passages sur le code initial avait 3 passages - y compris le préprocesseur. Je ne peux pas fournir un lien vers la source de cette déclaration, ni me souvenir du compilateur. –

1

Placez le code dans l'en-tête, en dehors de la définition de classe. Ou placez-le dans un fichier .tcc et incluez-le au bas de l'en-tête.

+0

pas vraiment pertinent ici. merci quand même –

2

Essayez quelque chose comme:

template <typename T> class Matrix; 
template <typename T> std::ostream& operator<<(std::ostream& ostr, const Matrix<T>& m); 

template <Typename T> 
class Matrix 
{ 
    public: 

     friend ostream& operator<< <T> (ostream& ostr, const Matrix<K>& inputMatrix); 
}; 

// This must be in the same translation unit as the class definition! 
template<typename T> 
ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix) 
{ 
    // ... 
    return ostr; 
} 

Translation unit reference

re-re-modifié pour les commentaires adressés par aschepler et dribeas.

+0

oups, juste ajouté cela comme une réponse, et ont maintenant supprimé ... – Nim

+0

Je pense que vous avez besoin de 'Const Matrix &' dans la définition de la fonction. (La déclaration peut utiliser le nom de classe injecté 'Matrix' pour signifier' Matrix ', mais ce n'est pas visible à la définition.) – aschepler

+0

@aschepler, ce problème devrait être corrigé. Vous avez raison à propos de la deuxième chose aussi - dans la classe, j'aurais pu dire 'Matrix' au lieu de' Matrix '. Ce qui est bizarre, c'est d'avoir à utiliser un autre identifiant que 'T' dans la déclaration de classe de l'opérateur.Peut-être que c'est une anomalie de la version de GCC que j'ai utilisée, ou peut-être que c'est une extension Visual Studio qui vous permet de faire cela. Est-ce que quelqu'un sait ce que la norme dit? – luke