Какой синтаксис для перегрузки оператора == как свободной функции с шаблонными параметрами? - PullRequest
4 голосов
/ 06 июня 2011

У меня есть набор полиморфных классов, таких как:

class Apple {};
class Red : public Apple {};
class Green : public Apple {};

И бесплатные функции, которые их сравнивают:

bool operator==(const Apple&, const Apple&);
bool operator< (const Apple&, const Apple&);

Я создаю копируемый класс-обертку, который позволит мне использовать классы Red и Green в качестве ключей в картах STL, сохраняя при этом их полиморфное поведение.

template<typename Cat>
class Copy
{
public:
    Copy(const Cat& inCat) : type(inCat.clone()) {}
    ~Copy() { delete type; }
    Cat* operator->() { return type; }
    Cat& operator*() { return *type; }
private:
    Copy() : type(0) {}
    Cat* type;
};

Я хочу, чтобы тип Copy<Apples> был как можно более взаимозаменяемым с Apples. Есть еще несколько функций, которые я должен добавить к классу Copy выше, но сейчас я работаю над бесплатной функцией для operator==, как показано ниже:

template<typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e) {
    return *copy == e;
}

Вот часть моего кода тестирования:

Red red;
Copy<Apple> redCopy = red;
Copy<Apple> redCopy2 = redCopy;
assert(redCopy == Red());

Но компилятор говорит мне

../src/main.cpp:91: error: no match for ‘operator==’ in ‘redCopy == Red()’

Как мне узнать, что мой оператор == выше? Я подозреваю, что ответ может быть в добавлении некоторого неявного кода преобразования где-то, но я не уверен, что делать.

Ответы [ 3 ]

8 голосов
/ 07 июня 2011

Ваш шаблон объявлен как

template <typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e)

Это не соответствует redCopy == Red(), поскольку Red() имеет тип Red, поэтому компилятор выводит Red в качестве типа второго аргументато есть Cat = Red, но затем он ожидает, что тип первого аргумента будет Copy<Red>, а это не так (тип redCopy равен Copy<Apple>).

ЧтоВы действительно хотите выразить что-то вроде

template <typename Cat>
bool operator==(const Copy<Cat>& copy, const something-that-derives-from-Cat& e)

Самый простой способ сделать это, это добавить второй параметр шаблона:

template <typename Cat, typename DerivedFromCat>
bool operator==(const Copy<Cat>& copy, const DerivedFromCat& e)

Конечно, это не даеткомпилятор для обеспечения того, чтобы DerivedFromCat на самом деле был производным от Cat.Если вы хотите этого, вы можете использовать boost::enable_if:

template <typename Cat, typename DerivedFromCat>
typename enable_if<is_base_of<Cat, DerivedFromCat>, bool>::type
operator==(const Copy<Cat>&, const DerivedFromCat& e)

Но это может быть немного излишним ...

3 голосов
/ 07 июня 2011

@ HighCommander4 объяснил, что здесь не так. Альтернативное решение - отключить вычет для второго параметра operator==. Тип второго параметра затем определяется исключительно на основе первого аргумента оператора ==:

template<typename T> struct identity { typedef T type; };

template<typename Cat>
bool operator==(const Copy<Cat>& copy, typename identity<Cat>::type const& e) {
    return *copy == e;
}

Если вы сделаете это так, то нет никакого противоречия относительно того, какой тип Cat должен обозначать, и operator== будет работать так, как ожидается.

3 голосов
/ 07 июня 2011

Но ... Как вы ожидаете, что это будет работать?Вы объявили оператор шаблона

template<typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e)

, означающий, что тип в RHS совпадает с аргументом шаблона в LHS (Cat в обоих случаях).Тем не менее, вы ожидаете, что он будет вызван в случае

redCopy == Red()

, где redCopy равно Copy<Apple>.Как?

Примечание: аргумент шаблона для redCopy равен Apple, а не Red.Ваш оператор шаблона просто не может соответствовать этим типам.

Если бы вы объявили redCopy как

Copy<Red> redCopy;

, тогда ваш оператор работал бы.Или, если вы сделали

redCopy == Apple()

, ваш оператор также будет работать.Но когда вы смешиваете типы, такие как ваш

Copy<Apple> redCopy;
redCopy == Red();

, это просто не может работать.Каково ваше намерение в этом случае?

...