在 API 设计中,什么时候我应该更喜欢长度为 2 std::tuple 而不是一对?

In API design, when should I prefer a length-2 std::tuple over a pair?

我正在编写一个小型库,其中有一些 API 函数返回两个东西(不同类型)。我宁愿不为此声明一个结构;所以我正在考虑返回 std::pair<foo, bat>。但是 - 也许在现代我应该更喜欢返回 std::tuple<foo, bar> 而不是?

更一般地说,什么时候元组应该优先于元组,什么时候元组更合适?

But - perhaps in these modern times I should prefer returning std::tuple<foo, bar> instead?

More generally, when should a tuple be prefered over a pair, and when is pair the more appropriate construct?

好吧,如果您想使用(元)算法而不是 std::pair 而不是 std::pair

,它可能会很有用

最后,这完全取决于您的实际用例,不知道就无法回答。

如果您遇到的情况可以保证在本质上匹配一对类型(在上下文中语义相关),您最好使用 std::pair 来反映 API 中的那些语义。

如果您不确定,请使用 std::tuple 来保持 API 设计的未来灵活性。

另一种方法是简单地使用您自己的结构,这些结构清楚地为值命名语义:

 template<typename T>
 struct point2D {
      T x;
      T y;
 };

 template<typename T>
 struct point3D {
      T x;
      T y;
      T z;
 };

 template<typename Key, typename Value>
 struct Item {
     Key key:
     Value value;
 };

而不是 std::tuple<T,T>std::pair<T,T>std::tuple<T,T,T>

元组用于包装多个值,这些值之间可能有关系,也可能没有关系。

成对用于环绕两对值,这些值彼此之间存在关系,例如。一个键值对将有两个值,一个是键,另一个是值,它们彼此有关系,例如。在哈希图中,其中键指向对或值。

它真的取决于你希望一切如何工作等等。

我经常看到正确的 API 调用或库(与数学相关)return 结构或 class 即使容器有两个值。

但如果必须的话,我同意@Bauss,如果值是键值对,则使用std::pair,例如"table id, string name"。

但是如果元组不是键值但都是实际值例如位置是 XY 坐标 (int x, int y) 使用 std::tuple.

警告:以下是个人观点:

在计算机科学中,只有三个有趣的数字:

  • 一个
  • N

因为我们要么处理某物、某物或某物的缺失。例如 average(a0 , a1)average(a0, ...aI) 的特例,其中 I 是集合中的每个整数 (0 <= I < N)。

因此 std::pair 在逻辑上是 N 元组的特殊化,因此不需要。

更糟糕的是,使用 pair 假定项目数始终为 2,并将其烘焙到界面中。这显然是一个错误,因为我们正在用未来进行非破坏性更改的能力换取零收益。

第一次编写 STL 时,没有可变参数模板,只有三个成对用例:-

  1. 作为 equal_range 等的范围

  2. 作为从 map::insert

  3. 返回的状态迭代器
  4. 作为 map 中的 key/value 对。

然后 boost 伴随着元组等现代思想而来。作为一个非官方库,boost 能够模拟带有自动生成重载页面的可变参数模板。在每个编译器附带的标准化 API 中,这是不可想象的。

现在我们有了可变参数模板。除了不幸地融入地图界面之外,没有任何理由比 tuple

更喜欢 pair

您应该为此声明一个结构。

get<0>(x)get<1>(x),甚至 post-C++11 的 get<Foo>(x)get<Bar>(x),意义不大 and/or 惯用语比 x.foox.bar.

tuples 最适合按顺序标识的非统一类型的事物。

pairs 是在 C++11 之前编写的 tuple

pairtuple(以及 array,而我们正在使用)都是元组类的,因为它们支持 std::tuple_sizeget<N> .

许多类型使用 pair 而不是具有正确命名字段的结构,这被认为是 std 库中的一个错误。即,如果map使用struct KV{ Key key; Value value; },那就更好了。

现在,元编程支持 KV 作为通用对也很好。因此,tuple_sizeget<0> 等。但是丢弃命名字段通常不是一个好主意。名字有力量。

在 C++17 中,简单的 structs 开始使用结构化绑定,即使您不使用它们 "tuple-like".

如果你确实有一些东西的身份是由它们的非统一类型的顺序决定的,tuple 是可行的方法。 pair 几乎是遗留类型。 pairtuple 有一些优势,但 tuple 继续改进以删除它们(如 tuple 的隐式初始化)。