Implementing comparison operators via tuple and tie is a good idea?

(Note: tuple and tie can be taken from Boost or C ++ 11.)
When writing small structures with two elements, I sometimes prefer to choose std::pair , because everything necessary is already done for this data type, for example, operator< for strict-weak order.
Disadvantages, although they are rather useless variable names. Even if I myself created this typedef , I won’t remember in 2 days that the first and the second accurate, especially if they are both of the same type. This gets even worse for more than two participants, as the pair attachment sucks in pretty much.
Another option for this is tuple , either from Boost or C ++ 11, but in reality it does not look better and clearer. Therefore, I return to writing the structures themselves, including any necessary comparison operators.
Since especially operator< can be rather cumbersome, I was thinking about getting around this whole mess by simply relying on the operations defined for tuple :

An operator< example, for example. for strictly weak ordering:

 bool operator<(MyStruct const& lhs, MyStruct const& rhs){ return std::tie(lhs.one_member, lhs.another, lhs.yet_more) < std::tie(rhs.one_member, rhs.another, rhs.yet_more); } 

( tie makes a tuple T& links from the arguments passed.)




Change The suggestion from @DeadMG for personal inheritance from tuple not bad, but it has some disadvantages:

  • If the operators are free (maybe friends), I need to inherit in public
  • With casting, my functions / operators ( operator= in particular) can be easily circumvented
  • With tie solution, I can leave some members if they are not relevant for ordering

Are there any flaws in this implementation that I need to consider?

+82
c ++ operators c ++ 11 tuples
Jun 02 '11 at 18:36
source share
4 answers

This, of course, will make it easier to record the correct operator than scanning it yourself. I would say that we consider a different approach if profiling shows that the comparison operation is a time-consuming part of your application. Otherwise, the ease of maintaining this should outweigh any potential performance issues.

+52
Jun 02 '11 at 19:07
source share

I ran into the same problem and my solution uses C ++ 11 variadic templates. Here is the code:

Part .h:

 /*** * Generic lexicographical less than comparator written with variadic templates * Usage: * pass a list of arguments with the same type pair-wise, for intance * lexiLessthan(3, 4, true, false, "hello", "world"); */ bool lexiLessthan(); template<typename T, typename... Args> bool lexiLessthan(const T &first, const T &second, Args... rest) { if (first != second) { return first < second; } else { return lexiLessthan(rest...); } } 

And .cpp for the base argument with no arguments:

 bool lexiLessthan() { return false; } 

Your example will now look like this:

 return lexiLessthan( lhs.one_member, rhs.one_member, lhs.another, rhs.another, lhs.yet_more, rhs.yet_more ); 
+5
May 10 '13 at 7:37
source share

In my opinion, you still do not solve the same problem as std::tuple replication, namely, you must know both the quantity and the name of each member variable, you duplicate it twice in the function. You can choose private inheritance.

 struct somestruct : private std::tuple<...> { T& GetSomeVariable() { ... } // etc }; 

This approach is a little more useless to start with, but you only maintain variables and names in one place, and not in every place for every statement that you want to overload.

+3
Jun 02 '11 at 19:13
source share

If you plan to use more than one operator overload or more methods from a tuple, I would recommend making tuple a member of the class or getting from a tuple. Otherwise, you do a lot more work. When deciding between them, it’s important to answer an important question: do you want your class to be a tuple? If not, I would recommend containing a tuple and restricting the interface using delegation.

You can create accessors to "rename" tuple elements.

+1
Jun 02 '11 at 19:51
source share



All Articles