模板类实现比较运算符

时间:2015-05-26 12:29:50

标签: c++ templates operator-overloading

将所有重载的比较运算符写入类是我的一项常见任务,因此我编写了一个模板类,如果派生类实现=,则实现<,< =,> =,!= =和<。它工作但是有很多演员和不那么明显的“奇怪的重复模板模式”,所以我想知道是否有更简单的解决方案?

template <class Derived>
class Comparable
{
public:

    bool operator!=(const Comparable<Derived>& other) {
        return !(static_cast<Derived*>(this)->operator==
                     (*static_cast<const Derived*>(&other)));
    }

    bool operator<=(const Comparable<Derived>& other) {
        return (static_cast<Derived*>(this)->operator==
                    (*static_cast<const Derived*>(&other)))
                || (static_cast<Derived*>(this)->operator<
                    (*static_cast<const Derived*>(&other)));
    }

    bool operator>(const Comparable<Derived>& other) {
        return !(static_cast<Derived*>(this)->operator==
                    (*static_cast<const Derived*>(&other)))
                && !(static_cast<Derived*>(this)->operator<
                    (*static_cast<const Derived*>(&other)));
    }

    bool operator>=(const Comparable<Derived>& other) {
        return !(static_cast<Derived*>(this)->operator<
                    (*static_cast<const Derived*>(&other)));
    }
};

1 个答案:

答案 0 :(得分:4)

如果评论中的描述不明显:

template <typename T>
struct Comparable {
   friend bool operator!=(T const & lhs, T const & rhs) { return !(lhs == rhs); }
   friend bool operator> (T const & lhs, T const & rhs) { return   rhs <  lhs;  }
// ...
};
class MyType : Comparable<MyType> {
   int data;
   friend bool operator==(MyType const & lhs, MyType const & rhs) {
      return lhs.data == rhs.data;
   }
   friend bool operator< (MyType const & lhs, MyType const & rhs) {
      return lhs.data <  rhs.data;
   }
  public:
// ...
};

当编译器遇到MyType a, b; a > b;查找操作符时,最终将执行ADL,它将查看MyTypeComparable<MyType>内部(因为这是一个基础),它将在其中找到实现你需要:bool operator>(MyType const&, MyType const&)

作为自由函数的运算符允许定义超出要比较的类型(在本例中为基数),同时使这些运算符仅通过ADL可用(两个参数中的一个必须为{{1} })。使用自由函数也提供类型对称,编译器将允许双方的隐式转换,在成员函数的情况下,它只允许在运算符的右侧进行转换。

为了完整起见,可以做的另一个技巧是将运算符作为模板添加到命名空间中,并附带一个标记,该标记可用于将该命名空间用于ADL目的:

Comparable<MyType>

技巧基本相同,只是在这种情况下,运算符不在基础内部,而是在与之关联的命名空间中。这个解决方案比前一个解决方案稍微好一点,因为它可以使用不同形式的误用,包括namespace operators { template <typename T> bool operator>(T const & lhs, T const & rhs) { return rhs < lhs; } // rest of the operators come here struct tag {}; } class MyType : operators::tag { int data; friend bool operator<(T const & lhs, T const & rhs) { return lhs.data < rhs.data; } //... }; 可以使模板运算符可用于所有类型。