5

我有一组多态类,例如:

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

以及比较它们的免费功能:

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

我正在设计一个可复制的包装类,它允许我在 STL 映射中使用类RedGreen作为键,同时保留它们的多态行为。

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==?我怀疑答案可能是在某处添加一些隐式转换代码,但我不确定该怎么做。

4

3 回答 3

9

您的模板声明为

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

这不匹配redCopy == Red(),因为Red()is 是 type 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)

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

于 2011-06-06T20:02:24.547 回答
3

@HighCommander4 解释了这里出了什么问题。另一种解决方案是禁用对 的第二个参数的扣除operator==。然后仅根据==-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==会按预期工作。

于 2011-06-06T20:30:07.727 回答
3

但是......你希望它如何工作?您声明了一个模板运算符

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

这意味着 RHS 上的类型与 LHS 上的模板参数相同(Cat在这两种情况下)。但是您希望在以下情况下调用它

redCopy == Red()

redCopy在哪里Copy<Apple>。如何?

注意:模板参数redCopyApple,不是Red。您的模板运算符根本不可能匹配这些类型。

如果您redCopy声明为

Copy<Red> redCopy;

那么你的运营商会工作。或者如果你这样做了

redCopy == Apple()

您的运营商也可以工作。但是当你混合你原来的类型时

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

它根本行不通。在这种情况下,您的意图是什么?

于 2011-06-06T20:03:23.283 回答