如何最好地重载operator <> <=> =但只写一个或两个比较函数?

use*_*020 21 c++ comparison operator-overloading

我有一个类型为std :: string的类.我想通过比较属性为类提供一些比较运算符函数,如<,>,==,<=和> =.

我的问题是:任何简单的方法或工具

(1)只写一个或两个函数,例如一个用于运算符<(和==),其他函数可以自动生成.

(2)甚至更简单,因为类比较取决于std::string其比较函数已经提供的类型属性.

Zet*_*eta 26

好奇地反复出现模板模式

在这种情况下,您提供了一个简单的基类,它实现了所有需要的运算符,并且只是继承它:

template <class T>
struct implement_relational_operators{
    friend bool operator<=(const T & a,const T & b){ return a < b || a == b; }
    friend bool operator>(const T &  a, const T & b){ return !(a <= b); }
    friend bool operator!=(const T &  a, const T & b){ return !(a == b);}
    friend bool operator>=(const T &  a, const T & b){ return !(a < b); }
};

template <class T>
struct scalar : public implement_relational_operators<scalar<T> >{
    T value;
    bool operator<(const scalar& o) const { return value < o.value;}
    bool operator==(const scalar& o) const { return value == o.value;}
};
Run Code Online (Sandbox Code Playgroud)

这并没有共同的缺点std::rel_ops(见下文).但是,您仍然需要实现operator<operator==.使用类似的技巧boost.

C++ 20 <=>可能会进一步改善这种情况(见下文).

std::rel_ops (在C++ 20中弃用)

std::rel_ops提供基于额外操作<==,所以你只需要编写两家运营商.

但是,它将在C++ 20中弃用,在这里a <=> b将被抛入混合.

要求

您只需要equality(operator=)和小于(operator<)比较运算符.其余部分可以自动生成std::rel_ops,因为以下内容成立:

a != b equal to !(a == b)
a <= b equal to (a < b) || (a == b)
a >= b equal to !(a < b)
a >  b equal to !(a <= b)
Run Code Online (Sandbox Code Playgroud)

请注意,这些效率低于手动编写它们的效率.

警告

但是,由于自己很容易为这些操作员提供服务,因此您应该花费额外的精力并编写它们.他们也有一些缺点,如R. Martinho Fernandes所说:

请注意,[他们]将无法正常工作,除非您:

  1. 添加using namespace std::rel_ops您使用运算符的每个上下文; 要么
  2. 添加using::operator!=; using::operator<=; using::operator>=; using::operator>;using namespace std::rel_ops的命名空间(在类的命名空间中是不可接受的,因为它不会被ADL拾取).


Pet*_*ker 8

你可以使用std::rel_ops,但这是错误的.这是一个不属于任何人工具箱的大锤.

通常的方法是定义operator==operator<了解班级的细节.剩下的四个运营商可以写成:

a != b!(a == b)

a <= b!(b < a)

a > bb < a

a >= b!(a < b)

  • @Casey - 这个模式的要点是能够用`=='写`!=`,并且当需要不等式时,能够用`<`来编写各种不等式.在某些情况下,没有有意义的`<`(例如复数),在这些情况下,用`<`写`==`是行不通的.使用单个比较和可能的否定来编写不等式比使用`||`或`&&`更有效.我已经重新检查了代码,据我所知,这是正确的.如果您仍然认为这是错误的,请提供一个示例. (4认同)

Pub*_*bby 5

一种选择是使用CRTP,如Barton Nackman技巧:

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

https://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick

// A class template to express an equality comparison interface.
template<typename T> class equal_comparable {
    friend bool operator==(T const &a, T const &b) { return  a.equal_to(b); }
    friend bool operator!=(T const &a, T const &b) { return !a.equal_to(b); }
};

class value_type
 // Class value_type wants to have == and !=, so it derives from
 // equal_comparable with itself as argument (which is the CRTP).
 : private equal_comparable<value_type> {
  public:
    bool equal_to(value_type const& rhs) const; // to be defined
};
Run Code Online (Sandbox Code Playgroud)