我有一组多态类,例如:

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

以及比较它们的免费功能:
bool operator==(const Apple&, const Apple&);
bool operator< (const Apple&, const Apple&);

我正在设计一个可复制的包装器类,该类将允许我将RedGreen类用作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()’

如何识别上面的运算符(operator)==?我怀疑答案可能是在某个地方添加一些隐式转换代码,但我不确定该怎么做。

最佳答案

您的模板声明为

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)

但这可能有点矫kill过正...

07-24 09:44
查看更多