Kyle Strand
Kyle Strand

Reputation: 16499

Convenient way to define all comparison operators for class with one numeric data member?

If I have a type that consists of a single numeric data member (say, an int) and various methods, is there a convenient way to tell the compiler to automatically generate all the obvious comparison operators?

I.e., instead of this (using inline instead of constexpr for C++03, of course):

class MyValueType
{
    private:
        int myvalue;
    public:
        constexpr bool operator<(MyValueType rhs) const { return myvalue < rhs.myvalue; }
        constexpr bool operator>(MyValueType rhs) const { return myvalue > rhs.myvalue; }
        constexpr bool operator>=(MyValueType rhs) const { return myvalue >= rhs.myvalue; }
        constexpr bool operator==(MyValueType rhs) const { return myvalue == rhs.myvalue; }
        /// .... etc
}

I want something like Ruby's Comparable mixin, which basically allows you to define one operator and let Ruby take care of the rest. And I'd even assume that the compiler-generated versions would probably be better than mine: should rhs be a const ref for each case? Should I define versions that take forwarding references? What if I forget one of the operators? Etc.

So...does something like this exist?

(Please forgive me if this is a duplicate; I assumed someone would have already asked this somewhere, because it seems like an obvious feature to want, but I can't find any.)

EDIT: Automatic generation of comparison operators has been proposed as a feature: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3950.html

Upvotes: 5

Views: 1761

Answers (3)

Severin Pappadeux
Severin Pappadeux

Reputation: 20080

While in general ADL/KL is blessed way to go (kudos to Dietmar Kuhl), there is Curiously Recurring Template Pattern which might be used to facilitate such task (I've implemented not all methods, but idea is clear enough, I hope)

template <typename D> struct B
{
    bool operator==(const D& rhs) const { return !(rhs < *(const D*)this ) && !(*(const D*)this < rhs); }
    bool operator!=(const D& rhs) const { return !(*(const D*)this == rhs); }
};

struct D: public B<D>
{
    int _value;

    D(int value): _value(value) {}

    bool operator< (const D& rhs) const {return this->_value < rhs._value;}
};

int main()
{
    D a(1);
    D b(2);
    D c(1);

    std::cout << (a == b) << " " << (a == c) << " " << (a != c) << std::endl;

    return 0;
}

Upvotes: 0

Mark B
Mark B

Reputation: 96241

Have you looked at boost operators (http://www.boost.org/doc/libs/1_56_0/libs/utility/operators.htm)? It defines a bunch of templates to help you automatically define operators in your class.

Upvotes: 2

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153820

The C++ way of doing this is to use a tag type and ADL. Here is a quick example:

namespace relational {
    struct tag {};

    template <typename T>
    bool operator== (T const& lhs, T const& rhs) { return !(rhs < lhs) && !(lhs < rhs); }
    template <typename T>
    bool operator!= (T const& lhs, T const& rhs) { return !(lhs == rhs); }

    template <typename T>
    bool operator> (T const& lhs, T const& rhs) { return rhs < lhs; }
    template <typename T>
    bool operator<= (T const& lhs, T const& rhs) { return !(rhs < lhs); }
    template <typename T>
    bool operator>= (T const& lhs, T const& rhs) { return !(lhs < rhs); }
}

struct foo: relational::tag {
    int value;
    foo(int value): value(value) {}
    bool operator< (foo const& other) const { return this->value < other.value; }
};

#include <iostream>
void compare(foo f0, foo f1) {
    std::cout << std::boolalpha
              << f0.value << " == " << f1.value << " => " << (f0 == f1) << '\n'
              << f0.value << " != " << f1.value << " => " << (f0 != f1) << '\n'
              << f0.value << " <  " << f1.value << " => " << (f0 <  f1) << '\n'
              << f0.value << " <= " << f1.value << " => " << (f0 <= f1) << '\n'
              << f0.value << " >  " << f1.value << " => " << (f0 >  f1) << '\n'
              << f0.value << " >= " << f1.value << " => " << (f0 >= f1) << '\n'
        ;
}
int main() {
    compare(foo(1), foo(2));
    compare(foo(2), foo(2));
}

Upvotes: 12

Related Questions