使用一个数字数据成员为 class 定义所有比较运算符的简便方法?
Convenient way to define all comparison operators for class with one numeric data member?
如果我有一个由单个数字数据成员(例如 int
)和各种方法组成的类型,是否有方便的方法告诉编译器自动生成所有明显的比较运算符?
即,而不是这个(对于 C++03,当然使用 inline
而不是 constexpr
):
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,它基本上允许您定义 one 运算符并让 Ruby 处理其余部分。而且我什至假设编译器生成的版本可能比我的更好:rhs
应该是每个案例的 const
ref 吗?我应该定义采用转发引用的版本吗?如果我忘记了其中一位接线员怎么办?等等
那么……有这样的东西吗?
(如果这是重复的,请原谅我;我假设有人已经在某个地方问过这个问题,因为它似乎是一个明显想要的功能,但我找不到任何。)
编辑: 自动生成比较运算符已被提议作为一项功能:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3950.html
执行此操作的 C++ 方法是使用标记类型和 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));
}
您是否看过升压运算符 (http://www.boost.org/doc/libs/1_56_0/libs/utility/operators.htm)?它定义了一堆模板来帮助您在 class.
中自动定义运算符
虽然总的来说 ADL/KL 是一种幸运的方式(Dietmar Kuhl 的荣誉),但有一个 Curiously Recurring Template Pattern 可以用来促进这样的任务(我没有实现所有的方法,但是想法够清楚了,我希望)
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;
}
如果我有一个由单个数字数据成员(例如 int
)和各种方法组成的类型,是否有方便的方法告诉编译器自动生成所有明显的比较运算符?
即,而不是这个(对于 C++03,当然使用 inline
而不是 constexpr
):
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,它基本上允许您定义 one 运算符并让 Ruby 处理其余部分。而且我什至假设编译器生成的版本可能比我的更好:rhs
应该是每个案例的 const
ref 吗?我应该定义采用转发引用的版本吗?如果我忘记了其中一位接线员怎么办?等等
那么……有这样的东西吗?
(如果这是重复的,请原谅我;我假设有人已经在某个地方问过这个问题,因为它似乎是一个明显想要的功能,但我找不到任何。)
编辑: 自动生成比较运算符已被提议作为一项功能:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3950.html
执行此操作的 C++ 方法是使用标记类型和 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));
}
您是否看过升压运算符 (http://www.boost.org/doc/libs/1_56_0/libs/utility/operators.htm)?它定义了一堆模板来帮助您在 class.
中自动定义运算符虽然总的来说 ADL/KL 是一种幸运的方式(Dietmar Kuhl 的荣誉),但有一个 Curiously Recurring Template Pattern 可以用来促进这样的任务(我没有实现所有的方法,但是想法够清楚了,我希望)
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;
}