为什么在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::vector
和std::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那样有用。
-
交换和旋转的噱头只是噱头。 对于那些以前没见过的人来说,他们是完全混淆的,因为几乎每个人都是这样,这些噱头只是软件工程的实践。
-
使用元组返回多个值远不如自我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.lastname
比std::get<1>(a)
更具说明性)。
这使得OP提到的转换成为元组唯一可行的用例。
我有一个感觉,许多使用Boost.Any和Boost.Variant(与一些工程),而不是Boost.Tuple。