【问题标题】:using make_tuple for comparison [duplicate]使用 make_tuple 进行比较[重复]
【发布时间】:2012-06-04 01:59:51
【问题描述】:

可能重复:
Implementing comparision operators via 'tuple' and 'tie', a good idea?

有时我需要写一些丑陋的仿函数
例如

lhs.date_ < rhs.date_ ||
lhs.date_ == rhs.date_ && lhs.time_ < rhs.time_ ||
lhs.date_ == rhs.date_ && lhs.time_ == rhs.time_ && lhs.id_ < rhs.id_ .....

这真的让我很生气。
所以我开始避免写以下内容:

std::make_tuple( lhs.date_, lhs.time_, lhs.id_ ) < 
    std::make_tuple(rhs.date_, rhs.time_, rhs.id_ );

我几乎很高兴,但请注意,我可能不是出于目的使用元组让我担心。

你能批评这个解决方案吗?
或者这是一个好习惯?
你如何避免这样的比较?

更新:
感谢您指向 std::tie 以避免复制对象。
并感谢您指出重复的问题

【问题讨论】:

  • std::make_tuple 复制您传递给它的对象(除非您使用std::refstd::cref)——要比较现有对象而不复制,请使用@ 987654327@ 或 std::tie 而不是 std::make_tuple
  • 如果你使用 std::tie 代替这是一个很好的做法,它使 operator

标签: c++ c++11 tuples idioms


【解决方案1】:

std::tuple 比较运算符的声明指出:

按字典顺序比较 lhs 和 rhs,即比较第一个元素,如果它们相等,比较第二个元素,如果它们相等,比较第三个元素,依此类推。

所以,除了有可能创建不需要的临时对象(可能已优化掉)之外,您正在做的事情对我来说似乎没问题。

请注意,等价表示!( lhs &lt; rhs ) &amp;&amp; !( rhs &lt; lhs )而不是lhs == rhs,这是相等。假设 equivalentequality 对您的班级意味着相同,这样就可以了。请注意,这与例如通过键访问 set/map 没有什么不同。

为了避免临时变量,您可以使用 std::tielvalue 引用 的元组添加到其参数:

std::tie( lhs.date_, lhs.time_, lhs.id_ ) < 
    std::tie( rhs.date_, rhs.time_, rhs.id_ );

以类似的方式,std::forward_as_tuple 创建一个 右值引用的元组

【讨论】:

  • IIRC“等效”表示=。所以元组存在这种风险,但在 OP 的情况下它可能是安全的。
  • @djechlin: equivalent 表示!( lhs &lt; rhs ) &amp;&amp; !( rhs &lt; lhs ),相当于你写的。为什么会有风险?
  • 谢谢。所以OP应该知道这与他使用==所做的不同。我不知道 OP 的日期类是如何实现的,但我可以想象 == 会上升到日期,而 会上升到第二个。
  • @djechlin:更新了我的答案,谢谢。
  • 为了效率,我至少会提到std::tiestd::forward_as_tuple
【解决方案2】:

使用 tie 而不是 make_tuple 可能会更好(取决于是否值得避免成员的复制/移动),否则,这将起作用,并且没有什么可怕的。

如果你仔细想想,许多 POD 结构基本上都是“命名元组”,而 C++ 实际上通过提供按成员相等比较(以及复制、移动等)来迎合这一点——在大多数此类情况下,扩展它以(字典)按成员小于比较也很有意义。但不幸的是,C++ 没有提供任何方法来指定成员的字典比较,除非明确地写出来。当然,在具有自省功能的语言中,它很容易添加,但在 C++ 中,则不然。

一个明显的答案是让你的类实际上是一个命名元组。与其拥有成员 int date_、int64_t time_ 和 string id_,不如从元组继承,并编写对用户隐藏元组的访问器方法。但是在这种情况下,您只是用比较实现中的丑陋来换取访问器实现中的丑陋,尚不清楚这是否更好。

你可以使用宏来包装丑陋,但这可能不是更好:

DEFINE_NAMED_TUPLE_CLASS(MyDate, int date, int64_t time, string id)
  ...
END_NAMED_TUPLE_CLASS

或者您可以构建自己的外部代码生成器,允许您预处理具有“named_tuple_class”的扩展 C++,只需将标记更改为“class”,然后定义比较运算符即可处理。但这是很多工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 2014-10-21
    • 1970-01-01
    • 2012-10-07
    • 2018-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多