通过“ tuple”和“ tie”实现比较运算符,这是一个好主意吗?

(注意: tupletie可以取自 Boost 或 C + + 11。)
当编写只包含两个元素的小结构时,我有时倾向于选择 std::pair,因为所有重要的事情都已经针对该数据类型完成了,比如用于严格弱排序的 operator<
不过,缺点是变量名几乎没什么用。即使我自己创建了 typedef,我也不会记得2天后 firstsecond到底是什么,特别是如果它们都是同一种类型。这对于两个以上的成员来说更糟糕,因为嵌套 pair非常糟糕。
另一个选项是 tuple,要么来自 Boost,要么来自 C + + 11,但它看起来并没有更好更清晰。所以我回过头来自己编写结构,包括任何需要的比较运算符。
由于特别是 operator<可以相当麻烦,我想绕过这整个混乱,仅仅依靠定义为 tuple的操作:

operator<的例子,例如严格弱排序:

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私有继承的建议并不坏,但它也有一些缺点:

  • 如果操作符是独立的(可能是朋友) ,则需要公开继承
  • With casting, my functions / operators (operator= specifically) can be easily bypassed
  • 使用 tie解决方案,如果某些成员对订单不重要,我可以省略它们

这个实现中有什么我需要考虑的缺点吗?

18334 次浏览

这肯定会使编写正确的操作符比自己滚动操作符更容易。如果分析显示比较操作是应用程序中耗时的部分,那么只考虑不同的方法。否则,维护它的容易程度应该超过任何可能的性能问题。

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

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

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

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

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

我遇到过同样的问题,我的解决方案使用 c + + 11可变模板:

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...);
}
}

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

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
);