2010-07-23 6 views
1

comprennent "stdafx.h"

#include "Record.h" 

template<class T>//If I make instead of template regular fnc this compiles 
//otherwise I'm getting an error (listed on the very bottom) saying 
// that operator << is ambiguous, WHY? 
ostream& operator<<(ostream& out, const T& obj) 
{ 
    out << "Price: " 
     << (obj.getPrice()) << '\t'//this line causes this error 
     << "Count: " 
     << obj.getCount() 
     << '\n'; 
    return out; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    vector<Record> v; 
    v.reserve(10); 
    for (int i = 0; i < 10; ++i) 
    { 
     v.push_back(Record(rand()%(10 - 0))); 
    } 
    copy(v.begin(),v.end(),ostream_iterator<Record>(cout, "\n")); 
    return 0; 
} 

//Record class 
class Record 
{ 
    private: 
     int myPrice_; 
     int myCount_; 
     static int TOTAL_; 
    public: 
     Record(){} 
     Record(int price):myPrice_(price),myCount_(++TOTAL_) 
     {/*Empty*/} 
     int getPrice()const 
     { 
      return myPrice_; 
     } 

     int getCount()const 
     { 
      return myCount_; 
     } 
     bool operator<(const Record& right) 
     { 
      return (myPrice_ < right.myPrice_) && (myCount_ < right.myCount_); 
     } 
}; 

int Record::TOTAL_ = 0; 

Erreur 2 Erreur C2593: 'opérateur < <' est ambiguopérateur << Ambigu

+0

Peut-être parce que 'getPrice()' n'est pas défini pour chaque type, donc le modèle ne fonctionne pas – Jordan

+1

Pouvez-vous poster le message d'erreur exact? Ils vous disent généralement exactement pourquoi (bien que de la manière la plus ronde possible, avec des modèles) – Cogwheel

+0

@Cogwheel J'ai ajouté ENTIER erreur msg je reçois. –

Répondre

4

Tout d'abord, vous devez lire le message d'erreur avec plus d'attention. Comme alternative, pensez à briser la déclaration haut, quelque chose comme ceci:

out << "Price: "; 
out << (obj.getPrice()); 
out << "\tCount: "; 
out << obj.getCount(); 
out << '\n'; 

Lorsque vous le faites, vous vous rendrez compte que ce qui cause vraiment le problème est pas où vous essayez d'imprimer getPrice(), mais où vous essayez d'imprimer "Price: ".

Le problème est dû au fait que le compilateur ne sait pas s'il faut utiliser la surcharge normale pour imprimer la chaîne ou pour utiliser le modèle défini pour l'imprimer. Ce dernier provoquerait une récursion infinie, et il ne pourrait pas réellement compiler car il nécessite un objet sur lequel vous pouvez/pouvez appeler getPrice et getCount pour compiler correctement - mais il a une signature qui correspond, donc le compilateur dit qu'il est ambigu, et c'est la fin de ça.

+0

merci pour cette explication. Donc je devine que le numéro de ligne fourni par le compilateur est faux? –

+0

mais qu'est-ce qui m'étonne pourquoi le compilateur n'a pas choisi de version spécialisée pour string et int? –

+1

@ A-ha: Il est assez typique pour le compilateur de lister une ligne ou deux après l'emplacement du vrai problème (généralement quand il arrive à quelque chose qui indique clairement que ce qui a déjà été traité a un problème). Il ne peut pas choisir l'un sur l'autre car ni l'un ni l'autre ne nécessite une conversion, donc ce sont des allumettes tout aussi bonnes. –

9

Le concept derrière operator<<(ostream &, ...) est que chaque classe peut avoir son propre surcharge, gérer cette classe spécifique d'une manière qui a du sens. Cela signifie que vous obtenez operator<<(ostream &, const Record &) qui gère les objets Record, et operator<<(ostream &, const std::string &) qui gère les chaînes standard, et operator<<(ostream &, const FooClass &) qui gère les objets FooClass. Chacune de ces fonctions sait comment gérer le type d'objet pour lequel elle a été déclarée, car chacune d'entre elles nécessite une gestion différente de. (Par ex getPrice()/getCount() pour Record ou getFoo()/getBar() pour FooClass.)

Votre modèle piétine piétiner le concept. En le définissant comme une fonction de modèle (qui correspondrait n'importe quelle classe), vous ne vous heurtez pas seulement aux nombreuses définitions de operator<<() déjà dans le standard/votre base de code, mais toutes les surcharges possibles.

Comment le compilateur peut-il décider d'utiliser operator<<(ostream &, const std::string &) ou votre modèle? Il ne peut pas, alors il jette ses mains dans le désespoir et abandonne. C'est ce que l'erreur vous dit.

+0

comme je suis d'accord avec vous en général je ne peux pas d'accord avec vous quand vous dites, et attendez une seconde et laissez-moi copier ... et coller ... o ici nous go "Comment le compilateur peut-il décider d'utiliser l'opérateur << (ostream &, const std :: string &) ou votre template?" Eh bien, le compilateur ne peut-il pas vérifier le type de l'argument, puis choisir le bon modèle? Le deuxième point que je voudrais faire est que le compilateur n'a pas de problème (dans ce cas) avec le choix du bon modèle parce que l'erreur est causée par la ligne à l'intérieur de ce modèle comme indiqué par moi dans mon message original. –

+0

Eh bien, la réponse de Jerry (que vous avez acceptée) ne dit rien de différent: "Le problème surgit parce que le compilateur ne sait pas s'il faut utiliser la surcharge normale pour imprimer la chaîne, ou utiliser le modèle défini pour imprimer IT out." C'est ce que "ambiguos" signifie: En utilisant les règles du langage, le compilateur se retrouve avec plus d'un 'operator <<()' qui irait, et ne peut pas décider lequel utiliser. Ne vous méprenez pas, il s'agit d'une * erreur de programmation *, pas une sorte de stupidité de la part du compilateur. Il ne peut pas lire dans les pensées; Votre code doit être sans ambiguïté. – DevSolar

0

La raison de l'erreur est que votre surcharge basé sur un modèle est en conflit avec une autre surcharge basé sur un modèle, et il n'y a aucune raison de préférer un modèle à l'autre: (. ostream devrait être un typedef pour basic_ostream<char, char_traits<char> >)

template<class charT, class traits> 
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*); 

template <class T> 
basic_ostream<char, char_traits<char> >& operator<< (basic_ostream<char, char_traits<char> >&, const T&); 

//which one is preferable when you ask for: cout << "literal";? 

L'idée de faire de votre surcharge un modèle est discutable, vu que la surcharge ne peut clairement gérer aucune autre classe que votre record.

Il existe probablement des techniques pour vous permettre de fournir une seule surcharge basée sur un modèle pour un certain nombre de classes similaires à des enregistrements avec une petite métaprogrammation de modèle (enable_if et traits), si telle est l'idée.

Questions connexes