为什么似乎没有人在C ++中使用元组,Boost Tuple Library或TR1的标准库?我已经阅读了很多C ++代码,我很少看到元组的使用,但我经常看到很多地方元组会解决许多问题(通常从函数中返回多个值)。
元组允许你做各种各样的酷事:
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);
元组还使得从函数返回多个变量变得更加容易,这可能是比交换值更常见的情况。使用对返回值的引用肯定不是很优雅。
我没有想到的元组有什么大的缺点吗?如果没有,为什么他们很少使用?他们慢了吗?或者只是人们不习惯他们?使用元组是个好主意吗?
答案 0 :(得分:122)
一个愤世嫉俗的答案是许多人用C ++编程,但不理解和/或使用更高级别的功能。有时这是因为他们不被允许,但许多人根本不尝试(甚至不理解)。
作为一个非提升示例:有多少人使用<algorithm>
中的功能?
换句话说,许多C ++程序员只是使用C ++编译器的C程序员,可能是std::vector
和std::list
。这就是使用boost::tuple
并不常见的一个原因。
答案 1 :(得分:40)
因为它尚未标准化。任何非标准的都有更高的障碍。由于程序员们吵着要他们,所以Boost的作品变得很受欢迎。 (hash_map跳跃于脑海)。但是,虽然元组很方便,但人们对此并不是那么压倒性和明确的胜利。
答案 2 :(得分:23)
C ++元组语法可能比大多数人想要的更冗长。
考虑:
typedef boost::tuple<MyClass1,MyClass2,MyClass3> MyTuple;
因此,如果你想广泛使用元组,你可以在任何地方获得元组typedef,或者你到处都会看到烦人的长类型名称。我喜欢元组。我在必要时使用它们。但它通常仅限于几种情况,例如N元素索引或使用多重映射来绑定范围迭代器对。它通常在非常有限的范围内。
与Haskell或Python相比,它看起来非常丑陋和hacky。当C ++ 0x到达此处并且我们得到'auto'关键字时,元组将开始变得更具吸引力。
元组的有用性与声明,打包和解压缩它们所需的击键次数成反比。
答案 3 :(得分:9)
对我来说,这是习惯,放下手:元组不会为我解决任何新问题,只有少数我已经可以处理好了。以旧式方式交换价值仍然感觉更容易 - 更重要的是,我并没有真正考虑如何更好地交换“更好”。它原样很好。
就个人而言,我认为元组不是返回多个值的好方法 - 听起来像是struct
的工作。
答案 4 :(得分:8)
但是如果要旋转三个值怎么办?
swap(a,b);
swap(b,c); // I knew those permutation theory lectures would come in handy.
好的,所以使用4个等值,最终n元组变得比n-1互换的代码少。如果您自己实现了一个三周期模板,那么使用默认交换,这将完成6个分配而不是4个分配,尽管我希望编译器能够解决简单类型的问题。
您可以提出互换不实用或不合适的情况,例如:
tie(a,b,c) = make_tuple(b*c,a*c,a*b);
打开包装有点尴尬。
但是,重点是,有一些已知方法可以处理元组有用的最常见情况,因此没有采用元组的紧迫性。如果不出意外,我不相信:tie(a,b,c) = make_tuple(b,c,a);
不会复制6份,因此对某些类型(收藏品最明显)完全不合适。随意说服我,元组对于“大型”类型是个好主意,说不是这样: - )
对于返回多个值,如果值是不兼容的类型,则元组是完美的,但如果调用者可能以错误的顺序获取它们,则某些人不喜欢它们。有些人根本不喜欢多个返回值,并且不想通过简化它们来鼓励使用它们。有些人更喜欢用于输入和输出参数的命名结构,并且可能无法使用棒球棒来说服使用元组。没有考虑品味。
答案 5 :(得分:7)
许多人指出,元组与其他功能一样没用。
交换和旋转的噱头只是噱头。对于那些以前没有见过它们的人来说,它们完全令人困惑,因为它几乎是每个人,这些噱头只是糟糕的软件工程实践。
使用元组返回多个值远不如自我文档那么替代 - 返回命名类型或使用命名引用。如果没有这种自我记录,很容易混淆返回值的顺序,如果它们是可相互转换的,并且不是更明智的。
答案 6 :(得分:6)
并非所有人都可以使用提升,而TR1尚未广泛使用。
答案 7 :(得分:5)
在嵌入式系统上使用C ++时,拉入Boost库变得复杂。它们彼此耦合,因此库大小增加。您返回数据结构或使用参数传递而不是元组。在Python中返回元组时,数据结构的顺序和返回值的类型只是不明确的。
答案 8 :(得分:4)
你很少看到它们,因为精心设计的代码通常不需要它们 - 在野外并没有很多情况下使用匿名结构优于使用命名结构。 由于所有元组真正代表的是一个匿名结构,因此大多数情况下的大多数编码器都是真实的。
假设我们有一个函数“f”,其中元组返回可能有意义。作为一般规则,这些功能通常很复杂,可能会失败。
如果“f”CAN失败,则需要状态返回 - 毕竟,您不希望呼叫者必须检查每个参数以检测故障。 “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”的回报。元组解决方案不提供这一关键功能,这使其成为任何库代码的劣质答案。
答案 9 :(得分:3)
当然元组可能很有用,但正如所提到的那样,有一些开销和一两个障碍你必须跳过才能真正使用它们。
如果你的程序一直找到你需要返回多个值或交换多个值的地方,那么去元组路线可能是值得的,但有时候用经典的方式做事情会更容易。
一般来说,并非每个人都已经安装了Boost,而且我当然不会轻易下载它并配置我的include目录来处理它的元组设施。我想你会发现已经使用Boost的人比非Boost用户更有可能在他们的程序中找到元组使用,并且来自其他语言的移民(Python浮现在脑海中)更容易对缺少元组感到不安在C ++中,而不是探索添加元组支持的方法。
答案 10 :(得分:1)
由于数据存储std::tuple
具有struct
和数组的最差特征;所有访问都是基于第n个位置,但是不能使用tuple
循环遍历for
。
因此,如果tuple
中的元素在概念上是一个数组,我将使用一个数组,如果元素在概念上不是一个数组,那么一个struct(具有命名元素)更易于维护。 (a.lastname
比std::get<1>(a)
更具说明性。
这使得OP提到的转换成为元组唯一可行的用例。
答案 11 :(得分:0)
我觉得很多人使用Boost.Any和Boost.Variant(有一些工程)而不是Boost.Tuple。