Удобный способ определения всех операторов сравнения для класса с одним числовым элементом данных?

Если у меня есть тип, состоящий из одного элемента числовых данных (например, int) и различных методов, есть ли удобный способ сказать компилятору автоматически генерировать все очевидные операторы сравнения?

I.e., вместо этого (конечно, используя inline вместо constexpr для С++ 03):

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
}

Я хочу что-то вроде Ruby Comparable mixin, которое в принципе позволяет вам определить одного оператора и позволить Ruby позаботиться об остальном. И я бы даже предположил, что версии с компилятором, вероятно, будут лучше, чем мои: должен ли rhs быть const ref для каждого случая? Должен ли я определять версии, которые пересылают ссылки? Что, если я забуду одного из операторов? Etc.

Итак... что-то вроде этого существует?

(Пожалуйста, простите меня, если это дубликат, я предположил, что кто-то уже спросил об этом где-то, потому что это похоже на очевидную возможность, но я не могу найти.)

EDIT: В качестве функции предлагается автоматическая генерация операторов сравнения: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3950.html

Ответ 1

С++ способ сделать это - использовать тип тега и ADL. Вот краткий пример:

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));
}

Ответ 2

Посмотрели ли вы на операторы boost (http://www.boost.org/doc/libs/1_56_0/libs/utility/operators.htm)? Он определяет набор шаблонов, которые помогут вам автоматически определять операторы в вашем классе.

Ответ 3

В то время как в целом ADL/KL - это благословенный способ (к сожалению, Dietmar Kuhl), существует любопытный повторяющийся шаблонный шаблон, который может быть использован для облегчения такой задачи (я реализовал не все методы, но идея достаточно ясна, Надеюсь)

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;
}