Неоднозначный оператор << - PullRequest
1 голос
/ 23 июля 2010
#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<<(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;

Ошибка 2 ошибка C2593: «оператор <<» является неоднозначным </strong>

Ответы [ 3 ]

9 голосов
/ 23 июля 2010

Концепция operator<<( ostream &, ... ) заключается в том, что каждый класс может иметь свою собственную перегрузку, обрабатывая этот конкретный класс способом, который имеет смысл.

Это означает, что вы получаете operator<<( ostream &, const Record & ), который обрабатывает объекты Record, и operator<<( ostream &, const std::string & ), который обрабатывает стандартные строки, и operator<<( ostream &, const FooClass & ), который обрабатывает объекты FooClass. Каждая из этих функций знает, как обрабатывать тип объекта, для которого она была объявлена, поскольку каждая из них требует различной обработки. (Например, getPrice() / getCount() для Record или getFoo() / getBar() для FooClass.)

Ваш шаблон попирает всю концепцию. Определив его как шаблонную функцию (которая будет соответствовать любому классу), вы не только столкнетесь со многими определениями operator<<(), уже имеющимися в стандартной / вашей кодовой базе, но и со всеми возможными перегрузки.

Как компилятор мог решить, использовать ли operator<<( ostream &, const std::string & ) или ваш шаблон? Не может, поэтому в отчаянии вскидывает руки и сдается. Вот что говорит вам ошибка.

4 голосов
/ 23 июля 2010

Во-первых, вам нужно прочитать сообщение об ошибке более внимательно. В качестве альтернативы рассмотрите возможность разбиения утверждения примерно так:

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

Когда вы это сделаете, вы поймете, что на самом деле причиной проблемы является не , когда вы пытаетесь распечатать getPrice(), но где вы пытаетесь распечатать "Price: ".

Проблема возникает из-за того, что компилятор не знает, использовать ли обычную перегрузку для распечатки строки или использовать определенный шаблон для ее распечатки. Последний вызовет бесконечную рекурсию, и он не может на самом деле компилироваться, так как для этого требуется объект, для которого вы можете / могли бы вызывать getPrice и getCount для правильной компиляции - но он имеет сигнатуру, которая соответствует, поэтому компилятор говорит это неоднозначно, и это конец.

0 голосов
/ 23 июля 2010

Причина ошибки заключается в том, что ваша шаблонная перегрузка конфликтует с другой шаблонной перегрузкой, и нет никаких причин предпочитать один шаблон другому:

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 должно быть typedef для basic_ostream<char, char_traits<char> >.)

Сама идея сделать вашу перегрузку шаблоном сомнительной, поскольку очевидно, что перегрузка не может обрабатывать любой другой класс, кроме вашей записи.

Вероятно, существуют методы, позволяющие вам обеспечить единую шаблонную перегрузку для ряда несвязанных классов, подобных Record, с небольшим шаблонным метапрограммированием (enable_if и traits), если это идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...