Ambiguous operator <<
#include "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<<(os开发者_如何学Pythontream& 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;
Error 2 error C2593: 'operator <<' is ambiguous
The concept behind operator<<( ostream &, ... )
is that every class can have its own overload, handling that specific class in a way that make sense.
That means you get operator<<( ostream &, const Record & )
which handles Record objects, and operator<<( ostream &, const std::string & )
which handles standard strings, and operator<<( ostream &, const FooClass & )
which handles FooClass objects. Each of these functions knows how to handle the object type it has been declared for, because each of them requires a different handling. (E.g. getPrice()
/ getCount()
for Record
, or getFoo()
/ getBar()
for FooClass
.)
Your template is trampling roughshod over the whole concept. By defining it as a template function (which would match any class), you not only collide with the many definitions of operator<<()
already in the standard / your codebase, but all possible overloadings.
How could the compiler decide whether to use operator<<( ostream &, const std::string & )
or your template? It cannot, so it throws up its hands in despair and gives up. That's what the error is telling you.
First, you need to read the error message more carefully. As an alternative, consider breaking the statement up, something like this:
out << "Price: ";
out << (obj.getPrice());
out << "\tCount: ";
out << obj.getCount();
out << '\n';
When you do, you'll realize that what's really causing the problem is not where you try to print out getPrice()
, but where you try to print out "Price: "
.
The problem is arising because the compiler doesn't know whether to use the normal overload to print out the string, or to use the template being defined to print it out. The latter would cause infinite recursion, and it couldn't actually compile since it requires an object on which you can/could call getPrice
and getCount
to compile correctly -- but it has a signature that matches, so the compiler says it's ambiguous, and that's the end of that.
The reason of the error is that your templated overload is conflicting with another templated overload, and there is no reason to prefer one template to another:
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";?
(ostream
should be a typedef for basic_ostream<char, char_traits<char> >
.)
The whole idea of making your overload a template is questionable, seeing that the overload clearly cannot handle any other class than your Record.
There probably are techniques to allow you to provide a single templated overload for a number of unrelated Record-like classes with a little template metaprogramming (enable_if and traits), if that is the idea.
精彩评论