How-To make C++ types comparable

Often, we find ourselves in a situation where we have some struct or class, and it would be convenient to compare one instance to another. Similarly, we may find that it is conceptually ideal as a key for some std::map we’re using.

This isn’t a particularly complex thing to achieve, but it introduces a lot of boilerplate code. Instead, we can use liberate/cpp/operators/comparison.h.

Header and inheritance
 1#include <liberate/cpp/operators/comparison.h>
 2
 3struct my_type
 4  : public liberate::cpp::comparison_operators<my_type>
 5{
 6  // ...
 7};
 8
 9my_type a, b;
10
11assert(a == b);

The liberate::cpp::comparison_operators struct adds a number of comparison operators to your class including operator==() – but the compilation of the above will nonetheless fail, because how to compare my_struct is unclear.

You will have to provide a function for performing this comparison, is_equal_to.

Make equality comparable
1struct my_type
2  : public liberate::cpp::comparison_operators<my_type>
3{
4  bool is_equal_to(my_type const & other) const
5  {
6    // do your comparison here
7  }
8};

How is this any better than implementing operator==() directly? Simply because the liberate class also provides an operator!=() from the same function.

The utility of this may become more apparent when considering less-than comparison instead.

Make less-than comparable
 1struct my_type
 2  : public liberate::cpp::comparison_operators<my_type>
 3{
 4  bool is_less_than(my_type const & other) const
 5  {
 6    // do your comparison here
 7  }
 8};
 9
10my_type a, b;
11
12if (a < b) { /* ... */ }
13if (a > b) { /* ... */ }
14if (a <= b) { /* ... */ }
15if (a >= b) { /* ... */ }

All of the above four operators are provided via the single is_less_than function. Providing both functions yields 6 operators altogether, enough for comparisions required for key types in std::map, etc.

Note

All operators are inline functions, so will not generate code unless you use them. This means that it’s entirely possible to provide only an implementation of e.g. is_equal_to so long as you never perform any less-than, greater-than or similar comparisons.

Sometimes it’s easier to make a type comparable with free functions when it already has defined an operator== and an operator<. You can do this very easily. It’s also possible to combine both approaches. There’s a simple macro for that.

Add operators as free functions
1LIBERATE_MAKE_COMPARABLE(my_type);