为什么在C ++中使用元组不是更常见?

为什么没有人在C ++中使用元组,无论是Boost Tuple库还是TR1的标准库? 我读过很多C ++代码,很less看到使用元组,但是我经常看到很多元组可以解决许多问题的地方(通常从函数返回多个值)。

元组允许你做这样的各种酷事:

tie(a,b) = make_tuple(b,a); //swap a and b 

这当然比这更好:

 temp=a; a=b; b=temp; 

当然你可以这样做:

 swap(a,b); 

但是如果你想旋转三个值呢? 你可以用元组来做到这一点:

 tie(a,b,c) = make_tuple(b,c,a); 

元组也使得从函数中返回多个variables要容易得多,这可能比交换值更为常见。 使用对返回值的引用当然不是很优雅。

我没有想到元组有什么大的缺点? 如果没有,为什么他们很less使用? 他们慢吗? 还是只是人们不习惯他们? 使用元组是一个好主意吗?

因为它还不是标准的。 任何非标准的事情都会有更高的障碍。 由于程序员们为此吵闹,因此Boost的部分已经变得stream行起来。 (hash_map想起来)。 但是,虽然元组是方便的,但它不是如此的压倒性的和明确的胜利,人们打扰它。

愤世嫉俗的回答是,很多人用C ++编程,但不理解和/或使用更高级别的function。 有时候是因为他们不被允许,但很多人根本就不去尝试(甚至不理解)。

作为一个非增强的例子:有多less人使用<algorithm>

换句话说,许多C ++程序员只是使用C ++编译器的C程序员,也许是std::vectorstd::list 。 这就是使用boost::tuple原因之一。

C ++元组语法可能比大多数人想要的要冗长得多。

考虑:

 typedef boost::tuple<MyClass1,MyClass2,MyClass3> MyTuple; 

所以,如果你想大量使用元组,你可以在任何地方得到元组typedef,或者在任何地方都会遇到烦人的长types名称。 我喜欢元组 我必要时使用它们。 但是它通常仅限于几种情况,比如N元素索引,或者使用multimaps来绑定范围迭代器对。 而且通常在一个非常有限的范围内。

与Haskell或Python相比,它们都很丑陋。 当C ++ 0x到达这里,我们得到'自动'关键字元组将开始看起来更有吸引力。

元组的有效性与声明,打包和解压缩所需的按键次数成反比。

对我来说,这是习惯,下手:元组没有为我解决任何新问题,只有less数我已经可以处理好了。 以旧式的方式交换价值仍然感觉更容易 – 更重要的是,我并不真正考虑如何交换“更好”。 这是足够好的。

就个人而言,我不认为元组是一个很好的解决scheme来返回多个值 – 听起来像一个struct的工作。

但是如果你想旋转三个值呢?

 swap(a,b); swap(b,c); // I knew those permutation theory lectures would come in handy. 

好吧,所以有了4等值,最终n元组变成比n-1变换更less的代码。 如果你自己实现了一个三循环的模板,默认情况下,这会执行6个任务,而不是4个任务,尽pipe我希望编译器能够解决简单types的问题。

您可以想出交换不便或不合适的情况,例如:

 tie(a,b,c) = make_tuple(b*c,a*c,a*b); 

解压有点尴尬。

但是,问题在于,处理元组适合的最常见的情况是已知的,因此不需要紧急组装元组。 如果没有别的,我不相信:

 tie(a,b,c) = make_tuple(b,c,a); 

不会做6个副本,完全不适合某些types(集合是最明显的)。 随意说服我说元组对于“大”types是一个好主意,通过说这不是:-)

对于返回多个值,元组是完美的,如果值是不兼容的types,但有些人不喜欢他们,如果调用方可能得到他们在错误的顺序。 有些人根本不喜欢多个返回值,也不想通过简单的方式来鼓励他们的使用。 有些人只是喜欢命名结构的参数,并可能不能用棒球棒说服使用元组。 没有考虑到味道。

正如很多人指出的那样,元组并不像其他function那样有用。

  1. 交换和旋转的噱头只是噱头。 对于那些以前没见过的人来说,他们是完全混淆的,因为几乎每个人都是这样,这些噱头只是软件工程的实践。

  2. 使用元组返回多个值远不如自我logging,然后是替代方法 – 返回指定types或使用命名引用。 如果没有这个自我logging,如果它们是可以相互转换的,而且没有更明智的话,那么很容易混淆返回值的顺序。

不是每个人都可以使用boost,TR1还没有广泛使用。

在embedded式系统上使用C ++时,拉入Boost库变得复杂。 它们彼此耦合,因此图书馆规模增长。 您返回数据结构或使用parameter passing而不是元组。 当在Python中返回元组时,数据结构的顺序和返回值的types只是不明确的。

当然,元组可以是有用的,但是正如前面提到的那样,在你真正使用它们之前,你需要跳过一些开销和障碍。

如果你的程序一直find你需要返回多个值或者交换多个值的地方,那么去元组path可能是值得的,但是否则有时候用经典的方式来做事情就更容易了。

一般来说,并不是每个人都已经安装了Boost,我当然不会经历下载它的麻烦,并且configuration我的包含目录来为它的元组工具使用它。 我想你会发现已经使用Boost的人更容易在非Boost用户的程序中find元组的使用,而来自其他语言的Python(想到Python)更可能仅仅因为缺less元组在C ++中,而不是探索添加元组支持的方法。

你很less看到它们,因为精心devise的代码通常不需要它们,在野外使用匿名结构优于使用命名结构的情况并不多见。 由于所有元组真正代表的是一个匿名结构,所以在大多数情况下,大多数编码者只是用真实的东西。

假设我们有一个函数“f”,其中元组的返回可能是有意义的。 作为一般规则,这些function通常很复杂,可能会失败。

如果“f”可能会失败,则需要状态返回 – 毕竟,您不希望调用者必须检查每个参数来检测失败。 “f”可能适合这种模式:

 struct ReturnInts ( int y,z; } bool f(int x, ReturnInts& vals); int x = 0; ReturnInts vals; if(!f(x, vals)) { ..report error.. ..error handling/return... } 

这不是很好,但看看替代是多么丑陋。 请注意,我仍然需要一个状态值,但代码不可读,不能更短。 这可能也是比较慢,因为我承担了与元组1复制的成本。

 std::tuple<int, int, bool> f(int x); int x = 0; std::tuple<int, int, bool> result = f(x); // or "auto result = f(x)" if(!result.get<2>()) { ... report error, error handling ... } 

另一个重大缺点是隐藏在这里 – “ReturnInts”我可以通过修改“ReturnInts”而不改变“f”的界面来添加改变的“f”的返回。 元组解决scheme不提供这个关键特性,这使得它成为任何库代码的低级答案。

作为一个数据存储std::tuple具有struct和数组最差的特性; 所有访问都是基于第n个位置,但是不能通过使用for循环迭代tuple

因此,如果tuple中的元素在概念上是一个数组,那么我将使用一个数组,并且如果这些元素在概念上不是一个数组,那么一个结构(具有命名元素)更易于维护。 ( a.lastnamestd::get<1>(a)更具说明性)。

这使得OP提到的转换成为元组唯一可行的用例。

我有一个感觉,许多使用Boost.Any和Boost.Variant(与一些工程),而不是Boost.Tuple。