0

I need to create a bunch of classes so that the instances of a particular type can be mutually compared.

I thought about writing a compare method, unique to each class, and then adding the following code to each class definition, replacing T with the name of the class I'm in:

bool operator== (const T& L, const T& R)        {return L.compare(R)==0;}
bool operator!= (const T& L, const T& R)      {return L.compare(R)!=0;}
bool operator< (const T& L, const T& R)       {return L.compare(R)<0;}
bool operator<= (const T& L, const T& R)        {return L.compare(R)<=0;}
bool operator> (const T& L, const T& R)       {return L.compare(R)>0;}
bool operator>= (const T& L, const T& R)      {return L.compare(R)>=0;}

This is kind of repetitive, though. Is there a more generic way of doing it? I guess I could write a macro for that, parametrizing it on T, but macros are not very cplusplusy now, are they? I also thought about inheritance and polymorphism, and from what I'm read about it (I have yet to use virtual classes; I'm new to C++), it seems like I'd be introducing an unecessary runtime overhead, as I'm not going to be needing uniform access those via base class pointers. Is there a better way of accomplishing it other than macros or copy-pasting?

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • @tacp I have, but couldn't come up with a good template-based solution so I thought I'd ask experienced C++ coders about how it's really done it the field. – Petr Skocik Apr 20 '13 at 22:07

3 Answers3

1

Boost.Operators

The header <boost/operators.hpp> supplies several sets of class templates (in namespace boost). These templates define operators at namespace scope in terms of a minimal number of fundamental operators provided by the class.

#include <boost/operators.hpp>
#include <cassert>

struct Integer : boost::totally_ordered<Integer>
{
    int value;
    Integer(int x) : value(x) {}
};

bool operator<(Integer lhs,Integer rhs)
{
    return lhs.value < rhs.value;
}
bool operator==(Integer lhs,Integer rhs)
{
    return lhs.value == rhs.value;
}

int main()
{
    Integer a(1), b(2), c(1);
    // We have defined only operator< and operator==
    assert(a < b);
    assert(a == c);
    // Other operators are provided automaticly:
    assert(a <= b);
    assert(b > a);
    assert(b >= a);
    assert(a != b);
}
Community
  • 1
  • 1
Evgeny Panasyuk
  • 9,076
  • 1
  • 33
  • 54
0

The closest I think you can get is providing operators for the base class and requiring all comparable classes to inherit from it. Implementing them as templated free functions isn't exactly a good idea as it will allow the compiler to attempt the operation on more than just the types you are interested in.

class AClass
{
public:
    int compare(const AClass& a) const
    {
        return this == &a ? 0 : 1; // i'm sure you can do the -1 / 1 stuff
    }

    friend bool operator==(const AClass& L, const AClass& R)
    {
        return L.compare(R) == 0;
    }
};

This will allow comparisons of AClass and all decendents.

Captain Obvlious
  • 19,754
  • 5
  • 44
  • 74
0

Without using boost:

#include <cassert>
struct Integer
{
    int value;
    Integer(int x) : value(x) {}
};

bool operator<(Integer lhs,Integer rhs)
{
    return lhs.value < rhs.value;
}
bool operator==(Integer lhs,Integer rhs)
{
    return lhs.value == rhs.value;
}

template< class T >
bool operator!= (const T& L, const T& R) { return !(L==R); }
template< class T >
bool operator<= (const T& L, const T& R) { return (L < R) || (L == R); }
template< class T >
bool operator>  (const T& L, const T& R) { return (!(L < R)) && (!(L == R)); }
template< class T >
bool operator>= (const T& L, const T& R) { return !(L < R); }

int main()
{
    Integer a(1), b(2), c(1);
    assert(a < b);
    assert(a <= b);
    assert(b > a);
    assert(b >= a);
    assert(a == c);
    assert(a != b);
}

Or closer to your original question:

#include <cassert>
struct Integer {
  int value;
  Integer(int x) : value(x) {}
  int compare(const Integer & rhs) const {
    return (value - rhs.value);
  }
};

template< class T >
bool operator== (const T& L, const T& R) { return L.compare(R)==0; }
template< class T >
bool operator!= (const T& L, const T& R) { return L.compare(R)!=0; }
template< class T >
bool operator<  (const T& L, const T& R) { return L.compare(R)<0; }
template< class T >
bool operator<= (const T& L, const T& R) { return L.compare(R)<=0; }
template< class T >
bool operator>  (const T& L, const T& R) { return L.compare(R)>0; }
template< class T >
bool operator>= (const T& L, const T& R) { return L.compare(R)>=0; }

int main() {
  Integer a(1), b(2), c(1);
  assert(a < b);
  assert(a <= b);
  assert(b > a);
  assert(b >= a);
  assert(a == c);
  assert(a != b);
}
Hal Canary
  • 2,154
  • 17
  • 17
  • 1
    A downside to this approach is you've now introduced potentially conflicting operators for builtins & other types (and potentially pages of errors of compiler errors on incorrect usage). I would, instead suggest introducing a `template class comparable`, where the operators are defined there. Usage would follow the curiously recurring template pattern. i.e. What Boost provides you with the Operators library. – Nathan Ernst Apr 21 '13 at 04:36