通过“元组”实现比较运算符和“领带”,是个好主意吗?

发布于 2024-11-13 09:04:25 字数 1136 浏览 4 评论 0原文

(注意:tupletie 可以取自 Boost 或 C++11。)
当编写只有两个元素的小型结构时,我有时倾向于选择 std::pair,因为所有重要的事情都已经针对该数据类型完成,例如严格的运算符operator -弱排序。
但缺点是变量名几乎无用。即使我自己创建了 typedef,两天后我也不会记得 firstsecond 到底是什么,特别是如果它们都是的话属于同一类型。对于两个以上的成员来说,情况会变得更糟,因为嵌套非常糟糕。
另一种选择是元组,来自 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 pairs 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挽袖吟 2024-11-20 09:04:26

这肯定会让编写正确的运算符比自己编写更容易。我想说,只有当分析显示比较操作是应用程序中耗时的部分时,才考虑使用不同的方法。否则,维护的便利性应该超过任何可能的性能问题。

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.

尾戒 2024-11-20 09:04:26

我遇到了同样的问题,我的解决方案使用 c++11 可变参数模板。代码如下:

.h 部分:

/***
 * Generic lexicographical less than comparator written with variadic templates
 * Usage:
 *   pass a list of arguments with the same type pair-wise, for intance
 *   lexiLessthan(3, 4, true, false, "hello", "world");
 */
bool lexiLessthan();

template<typename T, typename... Args>
bool lexiLessthan(const T &first, const T &second, Args... rest)
{
  if (first != second)
  {
    return first < second;
  }
  else
  {
    return lexiLessthan(rest...);
  }
}

以及不带参数的基本情况的 .cpp:

bool lexiLessthan()
{
  return false;
}

现在您的示例变为:

return lexiLessthan(
    lhs.one_member, rhs.one_member, 
    lhs.another, rhs.another, 
    lhs.yet_more, rhs.yet_more
);

I have come accross this same problem and my solution uses c++11 variadic templates. Here comes the code:

The .h part:

/***
 * Generic lexicographical less than comparator written with variadic templates
 * Usage:
 *   pass a list of arguments with the same type pair-wise, for intance
 *   lexiLessthan(3, 4, true, false, "hello", "world");
 */
bool lexiLessthan();

template<typename T, typename... Args>
bool lexiLessthan(const T &first, const T &second, Args... rest)
{
  if (first != second)
  {
    return first < second;
  }
  else
  {
    return lexiLessthan(rest...);
  }
}

And the .cpp for the base case without arguments:

bool lexiLessthan()
{
  return false;
}

Now your example becomes:

return lexiLessthan(
    lhs.one_member, rhs.one_member, 
    lhs.another, rhs.another, 
    lhs.yet_more, rhs.yet_more
);
Saygoodbye 2024-11-20 09:04:26

在我看来,您仍然没有解决与 std::tuple 解决的相同问题 - 也就是说,您必须知道每个成员变量的数量和名称,您正在复制它函数中两次。您可以选择私有继承。

struct somestruct : private std::tuple<...> {
    T& GetSomeVariable() { ... }
    // etc
};

这种方法一开始就有点混乱,但是您只需将变量和名称维护在一个位置,而不是在您希望重载的每个运算符的每个位置维护。

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 for private inheritance.

struct somestruct : private std::tuple<...> {
    T& GetSomeVariable() { ... }
    // etc
};

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.

梦里南柯 2024-11-20 09:04:26

如果您计划使用多个运算符重载或元组中的多个方法,我建议将元组设为类的成员或从元组派生。否则,你所做的工作会更多。在两者之间做出决定时,需要回答的一个重要问题是:您希望您的类成为元组吗?如果不是,我建议包含一个元组并通过使用委托来限制接口。

您可以创建访问器来“重命名”元组的成员。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文