Template class that implements comparison operators

I often have to write all overloaded comparison operators to a class, so I wrote a template class that implements <, <=,> = ,! = if the derived class implements == and <. It works, but it has a lot of castings and the not-so-obvious “Curiously Repeating Pattern Template,” so I wonder if there are simpler solutions?

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))); } }; 
+6
source share
1 answer

If this is not obvious from the description in the comment:

 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: // ... }; 

When the compiler encounters the search MyType a, b; a > b; MyType a, b; a > b; for the operator, it will end the execution of the ADL, which will look inside MyType and Comparable<MyType> (since this is the base), where it will find the implementation you need: bool operator>(MyType const&, MyType const&) .

Operators that are free functions allow a definition that is outside the type being compared (in this case, the database), making these operators available only through ADL (one of the two arguments must be Comparable<MyType> ). Using a free function also provides type symmetry, the compiler will allow implicit conversions on both sides, where in the case of a member function, it allows conversions only on the right side of the operator.


For completeness, you can do another trick: provide operators in the form of templates in the namespace along with a tag that can be used to cast this namespace for ADL purposes:

 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; } //... }; 

The trick is basically the same, except that in this case the operators are not inside the database, but in the namespace that is associated with it. This solution is slightly less enjoyable than the previous one, as it is open to various forms of abuse, including using namespace operators; that will make boilerplate operators available for all types.

+4
source

Source: https://habr.com/ru/post/987931/


All Articles