重载运算符== 作为具有模板化参数的自由函数的语法是什么?

What's the syntax to overload operator== as a free function with templated parameters?

本文关键字:自由 参数 函数 语法 是什么 运算符 重载      更新时间:2023-10-16

我有一组多态类,例如:

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()’

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

您的模板声明为

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)

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

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

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();

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

@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==将按预期工作。