定义运算符<对于一个结构体
我有时使用小型struct
作为映射中的键,因此我必须为它们定义一个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;
}
};
这看起来非常冗长并且容易出错。是否有更好的方法或一些简单的方法来自动定义 struct
或 class
的 operator<
?
我知道有些人喜欢使用类似 memcmp(this, &rhs, sizeof(MyStruct)) memcmp(this, &rhs, sizeof(MyStruct)) < 的东西。 0
,但如果成员之间有填充字节,或者如果有 char
字符串数组可能在空终止符后包含垃圾,则这可能无法正常工作。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
我会这样做:
I would do this:
在这种情况下,您可以使用
boost::tuple
- 它的 operator 按照您想要的方式工作。In this case you can use
boost::tuple<int, int, int>
- its operator< works just the way you want.我认为最简单的方法是坚持使用 <运算符用于所有比较,并且不要使用 >或==。以下是我遵循的模式,您可以遵循所有结构
I think the easiest way is to stick with the < operator for all comparisons and don't use > or ==. Below is the pattern I follow, and you can follow for all your structs
我知道的最好的方法是使用 boost tuple< /a>.它提供了内置的比较和构造函数等。
我也喜欢 Mike Seymors 通过 boost 的 make_tuple 使用临时元组的建议
The best way I know is to use a boost tuple. It offers among others a builtin comparison and constructors.
I also like Mike Seymors suggestion to use temporary tuples through boost's make_tuple
我通常这样实现字典排序:
请注意,它需要额外考虑浮点值(G++警告),对于那些像这样的东西会更好:
I usually implement lexicographical ordering this way:
Mind you it needs extra consideration for floating point values (G++ warnings), for those something like this would be better:
如果你不能使用 boost,你可以尝试类似的方法:
我想这可以避免任何宏,并且只要结构中的类型支持 <,它就应该可以工作。当然,这种方法存在开销,构造 is_gt ,然后如果其中一个值更大,则为每个参数构造多余的分支...
编辑:
根据注释进行修改,此版本现在应该短路为好吧,现在使用两个布尔值来保持状态(不确定是否有办法用单个布尔值来做到这一点)。
并
建立此类函子的集合以进行各种比较。
if you can't use boost, you could try something like:
I guess this avoids any macros, and as long as the types in the structure support <, it should work. Of course there is overhead for this approach, constructing is_gt and then superflous branches for each parameter if one of the values is greater...
Edit:
Modified based on comments, this version should now short-circuit as well, now uses two bools to keep state (not sure there's a way to do this with a single bool).
and
just build up a collection of such functors for various comparisons..
我刚刚学会了 boost::tuple 技巧,谢谢@Mike Seymour!
如果你买不起 Boost,我最喜欢的惯用语是:
我喜欢它,因为它将所有内容设置为并行结构,使错误和遗漏更容易发现。
但是,当然,无论如何你都会对此进行单元测试,对吧?
I just learned the
boost::tuple
trick, thanks, @Mike Seymour!If you can't afford Boost, my favorite idiom is:
which I like because it sets everything in parallel structure that makes errors and omissions easier to spot.
But, of course, you are unit testing this anyway, right?
我写了一个 perl 脚本来帮助我。例如给出:
它将发出:
代码(有点长):
I wrote a perl script to help me. For example given:
It would emit:
Code (it's a bit long):
当您可以在定义词典顺序的元素上生成迭代器时,您可以使用
中的std::lexicography_compare
。否则,我建议基于旧的三值比较函数进行比较,例如如下:
我在
compare
函数中包含了最后一个if
和return
为了一般性。我想它可以帮助维护严格遵守单个系统。否则,您可以在那里执行return Comparison( lhs.c, rhs.c )
(也许您更喜欢这样做)。干杯& hth.,
- 阿尔夫
When you can produce iterators over the elements defining the lexicographic order you can use
std::lexicographic_compare
, from<algorithm>
.Otherwise I suggest basing comparisons on old three-value compare functions, e.g. as follows:
I included the last
if
andreturn
in thecompare
function just for generality. I imagine it can help maintenance to very rigidly adhere to a single system. Otherwise you could just do areturn compared( lhs.c, rhs.c )
there (and perhaps you prefer that).Cheers & hth.,
− Alf
如果三向比较比双向比较更昂贵,并且如果结构的更重要部分通常相等,则使用“偏差”参数定义字段比较函数可能会有所帮助,这样如果“偏差”为 false 时,当 a>b 时返回 true,当bias 为 true 时,如果 a>=b 则返回 true。然后,可以通过执行以下操作来找出是否 a>b:
请注意,将执行所有比较,即使 a.f1<>b.f1,但比较将是双向的而不是三向的。
If three-way comparisons are more expensive than two-way, and if the more-significant portions of the structures will often be equal, it may be helpful to define field comparison functions with a 'bias' parameter, such that if 'bias' is false, they will return true when a>b, and when bias is true, they will return true if a>=b. Then one can find out if a>b by doing something like:
Note that all comparisons will be performed, even if a.f1<>b.f1, but comparisons will be two-way instead of three-way.
这是一个相当老的问题,因此这里的所有答案都已过时。 C++11 提供了更优雅、更高效的解决方案:
为什么这比使用
boost::make_tuple
更好?因为make_tuple
将创建所有数据成员的副本,这可能会很昂贵。相比之下,std::tie
只会创建一个薄的引用的包装器(编译器可能会完全优化掉它)。事实上,上面的代码现在应该被认为是对具有多个数据成员的结构实现字典比较的惯用解决方案。
This is quite an old question and as a consequence all answers here are obsolete. C++11 allows a more elegant and efficient solution:
Why is this better than using
boost::make_tuple
? Becausemake_tuple
will create copies of all the data members, which can be costly.std::tie
, by contrast, will just create a thin wrapper of references (which the compiler will probably optimise away entirely).In fact, the above code should now be considered the idiomatic solution to implementing a lexicographical compare for structures with several data members.
其他人提到了
boost::tuple
,它为您提供了字典顺序比较。如果您想将其保留为具有命名元素的结构,则可以创建临时元组进行比较:在 C++0x 中,这变为
std::make_tuple()
。更新:现在 C++11 出现了,它变成了
std::tie()
,可以在不复制对象的情况下创建引用元组。有关详细信息,请参阅康拉德鲁道夫的新答案。Others have mentioned
boost::tuple
, which gives you a lexicographical comparison. If you want to keep it as a structure with named elements, you can create temporary tuples for comparison:In C++0x, this becomes
std::make_tuple()
.UPDATE: And now C++11 is here, it becomes
std::tie()
, to make a tuple of references without copying the objects. See Konrad Rudolph's new answer for details.