Kri*_*son 56 c++ operator-overloading
我有时structs
在地图中使用小键作为键,因此我必须operator<
为它们定义一个.通常,这最终看起来像这样:
struct MyStruct
{
A a;
B b;
C c;
bool operator<(const MyStruct& rhs) const
{
if (a < rhs.a)
{
return true;
}
else if (a == rhs.a)
{
if (b < rhs.b)
{
return true;
}
else if (b == rhs.b)
{
return c < rhs.c;
}
}
return false;
}
};
Run Code Online (Sandbox Code Playgroud)
这看起来非常冗长且容易出错.有没有更好的方法,或一些简单的方法来自动定义operator<
一个struct
或class
?
我知道有些人喜欢使用类似的东西memcmp(this, &rhs, sizeof(MyStruct)) < 0
,但是如果成员之间存在填充字节,或者如果char
在null终止符之后存在可能包含垃圾的字符串数组,则这可能无法正常工作.
Kon*_*lph 98
这是一个相当古老的问题,因此这里的所有答案都已过时.C++ 11允许更优雅和有效的解决方案:
bool operator <(const MyStruct& x, const MyStruct& y) {
return std::tie(x.a, x.b, x.c) < std::tie(y.a, y.b, y.c);
}
Run Code Online (Sandbox Code Playgroud)
为什么这比使用更好boost::make_tuple
?因为make_tuple
将创建所有数据成员的副本,这可能是昂贵的.std::tie
相比之下,只会创建一个瘦的引用包装(编译器可能会完全优化).
实际上,上面的代码现在应该被认为是对具有多个数据成员的结构进行词典比较的惯用解决方案.
Mik*_*our 19
其他人提到boost::tuple
,它给你一个字典比较.如果要将其保留为具有命名元素的结构,可以创建临时元组以进行比较:
bool operator<(const MyStruct& x, const MyStruct& y)
{
return boost::make_tuple(x.a,x.b,x.c) < boost::make_tuple(y.a,y.b,y.c);
}
Run Code Online (Sandbox Code Playgroud)
在C++ 0x中,这变成了std::make_tuple()
.
更新:现在,C++ 11就可以在std::tie()
不复制对象的情况下创建引用元组.有关详细信息,请参阅Konrad Rudolph的新答案.
我会这样做:
#define COMPARE(x) if((x) < (rhs.x)) return true; \
if((x) > (rhs.x)) return false;
COMPARE(a)
COMPARE(b)
COMPARE(c)
return false;
#undef COMPARE
Run Code Online (Sandbox Code Playgroud)
我认为最简单的方法是在所有比较中都使用 < 运算符,不要使用 > 或 ==。以下是我遵循的模式,您可以遵循所有结构
typedef struct X
{
int a;
std::string b;
int c;
std::string d;
bool operator <( const X& rhs ) const
{
if (a < rhs.a) { return true; }
else if ( rhs.a < a ) { return false; }
// if neither of the above were true then
// we are consdidered equal using strict weak ordering
// so we move on to compare the next item in the struct
if (b < rhs.b) { return true; }
if ( rhs.b < b ) { return false; }
if (c < rhs.c) { return true; }
if ( rhs.c < c ) { return false; }
if (d < rhs.d) { return true; }
if ( rhs.d < d ) { return false; }
// if both are completely equal (based on strict weak ordering)
// then just return false since equality doesn't yield less than
return false;
}
};
Run Code Online (Sandbox Code Playgroud)