Reputation: 16499
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
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
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
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