If you wrote a new class MyClass
, you might
want sometimes to write expressions like this:
MyClass x, y; /// some code initializing x and y if(x < y) { // do something } else if (x == y) { // do something else }
Even if you don’t need comparison operators
(<
, <=
, etc.) yourself, you
might find that someone attempts to use your class with Standard
Template Library operations that require you to define these operators.
For example, if you try to sort a vector of instances of your
class:
vector<MyClass> v; v.push_back(MyClass(3)); v.push_back(MyClass(1)); v.push_back(MyClass(2)); sort(v.begin(), v.end());
an attempt to compile this code fills the screen with diagnostics that look like this:
/usr/include/c++/4.2.1/bits/stl_heap.h:121: error: no match for 'operator<' in '__first. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator+ [with _Iterator = MyClass*, _Container = std::vector<MyClass, std::allocator<MyClass> >](((const ptrdiff_t&)((const ptrdiff_t*)(& __parent)))).__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = MyClass*, _Container = std::vector<MyClass, std::allocator<MyClass> >]() < __value'
Although this output is not easily readable by a human, after
some effort one can find in that pile of information the following
useful piece: no match for
‘operator<’
. What the compiler is unhappy about is that
the class MyClass
does not define a
<
operator. All you have to do is add to the
definition of MyClass
:
class MyClass { public: // constructors, etc… bool operator < (const MyClass& that) const { // some code returning bool return my_data_ < that.my_data_; } private: Int my_data_;
and the example compiles, runs, and sorts the vector. The same thing happens if you try to
use your class in std::set<MyClass>
or as a key in
std::map<MyClass, AnyOtherClass>
. While STL is
relatively undemanding and in most cases will be satisfied by the definition of only one <
operator, there might be cases when you want
to define several comparison operators or potentially all of them. For example, suppose you’ve
decided to write a Date
class that would encapsulate the
calendar date and you expect that other programmers might want to use all kinds of comparisons:
date1 >= date2
, etc. There are six comparison operators:
< |
> |
<= |
>= |
== |
!= |
From the point of view of C++, these operators could be written as six totally
independent functions, and nothing in C++ prevents you from writing each one any way you like.
However, the user of your class MyClass
would expect that if
instances of this class satisfy the inequality x1 < x2
,
then it must also be true that x1 <= x2
and that x2 > x1
. In other words, there are some logical relations between
these operators, and after writing each comparison operator, it would be a good idea to make
sure that these relations hold in order to avoid confusion. In fact, no additional work to
achieve this is necessary. There is an easy way to kill all six birds with one stone in two
steps.
In your class, define the following method:
class MyClass { public: // some code… // Returns negative int when *this < that, // 0 when *this == that and // positive int when *this > that. int CompareTo(const MyClass& that) const;
Define all six comparison operators by using the following macro inside the public section of your class:
SCPP_DEFINE_COMPARISON_OPERATORS(MyClass)
I have defined SCPP_DEFINE_COMPARISON_OPERATORS
in the file scpp_types.hpp as follows:
#define SCPP_DEFINE_COMPARISON_OPERATORS(Class) bool operator < (const Class& that) const { return CompareTo(that) < 0; } bool operator > (const Class& that) const { return CompareTo(that) > 0; } bool operator ==(const Class& that) const { return CompareTo(that) ==0; } bool operator <=(const Class& that) const { return CompareTo(that) <=0; } bool operator >=(const Class& that) const { return CompareTo(that) >=0; } bool operator !=(const Class& that) const { return CompareTo(that) !=0; }
In one long line, this macro defines all six comparison operators for you in a consistent
way. In order for this to work, the only thing you need to do is provide the CompareTo()
function in your class. If you ever decide to change the
definition of what you mean by >
or <=
for the instances of your class, you can simply edit that
function and the rest will behave accordingly while preserving all the relations one would expect
between different comparison operators.
Rule for this chapter to avoid errors when writing comparison operators:
18.220.245.140