Defining operator< for a struct
This is quite an old question and as a consequence all answers here are obsolete. C++11 allows a more elegant and efficient solution:
bool operator <(const MyStruct& x, const MyStruct& y) {
return std::tie(x.a, x.b, x.c) < std::tie(y.a, y.b, y.c);
}
Why is this better than using boost::make_tuple
? Because make_tuple
will create copies of all the data members, which can be costly. std::tie
, by contrast, will just create a thin wrapper of references (which the compiler will probably optimise away entirely).
In fact, the above code should now be considered the idiomatic solution to implementing a lexicographical compare for structures with several data members.
Others have mentioned boost::tuple
, which gives you a lexicographical comparison. If you want to keep it as a structure with named elements, you can create temporary tuples for comparison:
bool operator<(const MyStruct& x, const MyStruct& y)
{
return boost::make_tuple(x.a,x.b,x.c) < boost::make_tuple(y.a,y.b,y.c);
}
In C++0x, this becomes std::make_tuple()
.
UPDATE: And now C++11 is here, it becomes std::tie()
, to make a tuple of references without copying the objects. See Konrad Rudolph's new answer for details.
I would do this:
#define COMPARE(x) if((x) < (rhs.x)) return true; \
if((x) > (rhs.x)) return false;
COMPARE(a)
COMPARE(b)
COMPARE(c)
return false;
#undef COMPARE
In this case you can use boost::tuple<int, int, int>
- its operator< works just the way you want.
I think the easiest way is to stick with the < operator for all comparisons and don't use > or ==. Below is the pattern I follow, and you can follow for all your structs
typedef struct X
{
int a;
std::string b;
int c;
std::string d;
bool operator <( const X& rhs ) const
{
if (a < rhs.a) { return true; }
else if ( rhs.a < a ) { return false; }
// if neither of the above were true then
// we are consdidered equal using strict weak ordering
// so we move on to compare the next item in the struct
if (b < rhs.b) { return true; }
if ( rhs.b < b ) { return false; }
if (c < rhs.c) { return true; }
if ( rhs.c < c ) { return false; }
if (d < rhs.d) { return true; }
if ( rhs.d < d ) { return false; }
// if both are completely equal (based on strict weak ordering)
// then just return false since equality doesn't yield less than
return false;
}
};