Relational operator implementation dilemma

I am developing several classes that must support the operators != , > , <= And >= . These operators will be implemented in terms of the == and < operators.

At this point, I need to make a choice between inheritance¹ and force my consumers to use std::rel_ops ² manually.

[1] Inheritance (possible implementation):

 template<class T> class RelationalOperatorsImpl { protected: RelationalOperatorsImpl() {} ~RelationalOperatorsImpl() {} friend bool operator!=(const T& lhs, const T& rhs) {return !(lhs == rhs);} friend bool operator>(const T& lhs, const T& rhs) {return (rhs < lhs);} friend bool operator<=(const T& lhs, const T& rhs) {return !(rhs < lhs);} friend bool operator>=(const T& lhs, const T& rhs) {return !(lhs < rhs);} }; template<typename T> class Foo : RelationalOperatorsImpl< Foo<T> > { public: explicit Foo(const T& value) : m_Value(value) {} friend bool operator==(const Foo& lhs, const Foo& rhs) {return (lhs.m_Value == rhs.m_Value);} friend bool operator<(const Foo& lhs, const Foo& rhs) {return (lhs.m_Value < rhs.m_Value);} private: T m_Value; }; 

[2] std::rel_ops glue:

 template<typename T> class Foo { public: explicit Foo(const T& value) : m_Value(value) {} friend bool operator==(const Foo& lhs, const Foo& rhs) {return (lhs.m_Value == rhs.m_Value);} friend bool operator<(const Foo& lhs, const Foo& rhs) {return (lhs.m_Value < rhs.m_Value);} private: T m_Value; }; void Consumer() { using namespace std::rel_ops; //Operators !=, >, >=, and <= will be instantiated for Foo<T> (in this case) on demand. } 

I mainly try to avoid code repetition. Any thoughts on which method "feels" better?

+4
source share
2 answers

Have you considered using boost and inherited your class from boost::less_than_comparable<T> and boost::equality_comparable<T> ? This is similar to your first suggestion, with some pros and cons. Pros: Avoid code duplication; Cons: creates a dependency on the increase.

Since boost is a very common C ++ library (if you are not using it anymore, you should seriously consider starting to use it), the compression ratio is obscured.

+5
source

I think std::rel_ops pretty nice, but you should think about it first: std::rel_ops provides operators as template functions that take two parameters of the same type. Since most conversions (including, for example, arithmetic promotions and custom conversions) are not performed when the template argument is output, this means that you cannot use any of these additional operators (for example != ) With such transformations.

eg. if you have a class MyInt that tries to behave like a regular integer, you could write conversion functions / constructors or boilerplate operators so you can do

 MyInt x, y; x < 5; 9 == x; 

but

 x > 5; 30 <= x; 

will not work (with std::rel_ops ) because the two arguments are of different types, so the template argument will not be output.

+1
source

All Articles