通过“元组”实现比较运算符和“领带”,是个好主意吗?
(注意:tuple
和 tie
可以取自 Boost 或 C++11。)
当编写只有两个元素的小型结构时,我有时倾向于选择 std::pair,因为所有重要的事情都已经针对该数据类型完成,例如严格的运算符operator
-弱排序。
但缺点是变量名几乎无用。即使我自己创建了 typedef
,两天后我也不会记得 first
和 second
到底是什么,特别是如果它们都是的话属于同一类型。对于两个以上的成员来说,情况会变得更糟,因为嵌套对
非常糟糕。
另一种选择是元组,来自 Boost 或 C++11,但这看起来并没有更好、更清晰。所以我回去自己编写结构,包括任何需要的比较运算符。
特别是由于 operator<
可能相当麻烦,我想通过仅依靠为 tuple
定义的操作来避免整个混乱:
operator<
的示例code>,例如对于严格弱排序:(
bool operator<(MyStruct const& lhs, MyStruct const& rhs){
return std::tie(lhs.one_member, lhs.another, lhs.yet_more) <
std::tie(rhs.one_member, rhs.another, rhs.yet_more);
}
tie
从传递的参数中创建 T&
引用的 tuple
。)
编辑: @DeadMG 从 tuple
私有继承的建议并不是一个坏建议,但它有很多缺点:
- 如果运算符是独立的(可能是朋友),我需要
- 通过强制转换 公开继承,我的函数/运算符(特别是
operator=
)可以很容易地绕过 - 使用
tie
解决方案,我可以省略某些与排序无关的成员
。我需要解决此实现中的任何缺点 考虑?
(Note: tuple
and tie
can be taken from Boost or C++11.)
When writing small structs with only two elements, I sometimes tend to choose a std::pair
, as all important stuff is already done for that datatype, like operator<
for strict-weak-ordering.
The downsides though are the pretty much useless variable names. Even if I myself created that typedef
, I won't remember 2 days later what first
and what second
exactly was, especially if they are both of the same type. This gets even worse for more than two members, as nesting pair
s pretty much sucks.
The other option for that is a tuple
, either from Boost or C++11, but that doesn't really look any nicer and clearer. So I go back to writing the structs myself, including any needed comparision operators.
Since especially the operator<
can be quite cumbersome, I thought of circumventing this whole mess by just relying on the operations defined for tuple
:
Example of operator<
, e.g. for strict-weak-ordering:
bool operator<(MyStruct const& lhs, MyStruct const& rhs){
return std::tie(lhs.one_member, lhs.another, lhs.yet_more) <
std::tie(rhs.one_member, rhs.another, rhs.yet_more);
}
(tie
makes a tuple
of T&
references from the passed arguments.)
Edit: The suggestion from @DeadMG to privately inherit from tuple
isn't a bad one, but it got quite some drawbacks:
- If the operators are free-standing (possibly friends), I need to inherit publicly
- With casting, my functions / operators (
operator=
specifically) can be easily bypassed - With the
tie
solution, I can leave out certain members if they don't matter for the ordering
Are there any drawbacks in this implementation that I need to consider?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这肯定会让编写正确的运算符比自己编写更容易。我想说,只有当分析显示比较操作是应用程序中耗时的部分时,才考虑使用不同的方法。否则,维护的便利性应该超过任何可能的性能问题。
This is certainly going to make it easier to write a correct operator than rolling it yourself. I'd say only consider a different approach if profiling shows the comparison operation to be a time-consuming part of your application. Otherwise the ease of maintaining this should outweigh any possible performance concerns.
我遇到了同样的问题,我的解决方案使用 c++11 可变参数模板。代码如下:
.h 部分:
以及不带参数的基本情况的 .cpp:
现在您的示例变为:
I have come accross this same problem and my solution uses c++11 variadic templates. Here comes the code:
The .h part:
And the .cpp for the base case without arguments:
Now your example becomes:
在我看来,您仍然没有解决与 std::tuple 解决的相同问题 - 也就是说,您必须知道每个成员变量的数量和名称,您正在复制它函数中两次。您可以选择
私有
继承。这种方法一开始就有点混乱,但是您只需将变量和名称维护在一个位置,而不是在您希望重载的每个运算符的每个位置维护。
In my opinion, you're still not addressing the same issue as the
std::tuple
solves- namely, you have to know both how many and the name of each member variable, you're duplicating it twice in the function. You could opt forprivate
inheritance.This approach is a little bit more of a mess to begin with, but you're only maintaining the variables and names in one place, instead of in every place for every operator you wish to overload.
如果您计划使用多个运算符重载或元组中的多个方法,我建议将元组设为类的成员或从元组派生。否则,你所做的工作会更多。在两者之间做出决定时,需要回答的一个重要问题是:您希望您的类成为元组吗?如果不是,我建议包含一个元组并通过使用委托来限制接口。
您可以创建访问器来“重命名”元组的成员。
If you plan to use more than one operator overload, or more methods from tuple, I'd recommend making tuple a member of the class or derive from tuple. Otherwise, what you're doing is a lot more work. When deciding between the two, an important question to answer is: Do you want your class to be a tuple? If not I would recommend containing a tuple and limiting the interface by using delegation.
You could create accessors to "rename" the members of the tuple.