只有两个成员的 std::pair 和 std::tuple 之间的区别?

Posted

技术标签:

【中文标题】只有两个成员的 std::pair 和 std::tuple 之间的区别?【英文标题】:Difference between std::pair and std::tuple with only two members? 【发布时间】:2011-10-04 22:50:54 【问题描述】:

std::pair 和只有两个成员的std::tuple 之间有区别吗? (除了std::pair 需要两个而且只有两个成员,tuple 可能有更多或更少......)

【问题讨论】:

【参考方案1】:

有一些区别:

    标准并不要求std::tuple 永远是standard-layout。如果TY 都是标准布局,则每个std::pair<T, Y> 都是标准布局。

    获取pair 的内容比获取tuple 的内容要容易一些。你必须在tuple 的情况下使用函数调用,而pair 的情况只是一个成员字段。

但仅此而已。

【讨论】:

"从一对中取出数据比从一个元组中取出数据要容易一些。有点。"我注意到。 :P 虽然.first.second 很方便,但如果代码更改需要第三个(或更多)成员,它们也无济于事。我注意到我倾向于使用std::get,无论在任何Getter中,我都不需要更改所有内容,只需更改数据类型和任何make_pair调用make_tuple调用。 在什么方面成员访问比函数调用更容易? @Yakk:嗯,我按“。”我的 IDE 会显示一个成员列表。我不认为人们需要说明这一点。 我想知道 c++17 中的结构化绑定是否已经使这个答案的第 1 点和第 2 点无效?如果是这样,请也添加一个 c++17 版本。 @sandthorn:结构化绑定如何使tuple 成为标准布局?【参考方案2】:

std::tuple 的名称较长(多出一个字符)。更多这些字符是用右手输入的,因此对大多数人来说更容易输入。

也就是说,std::pair 只能有两个值 - 不能是零、一、三或更多。两个值。然而,元组对值的数量几乎没有语义限制。因此,std::pair 是一种更准确、类型安全的类型,可以在您实际想要指定一对值时使用。

【讨论】:

哈哈!太好了,您考虑了它的打字方式!我想指出的是,我输入 'pair' 的速度可能比 'tuple' 快 20% 以上。这是因为我的手交替输入每个字符,即。右轴:p,左轴:a,右轴:i,左轴:r。至少对我来说,我发现这样做更容易! - 但你仍然可以得到 +1! "因此,如果您确实想指定一对值,则 std::pair 是一种更准确、类型安全的类型。"类型安全或“准确”,它只是(可以说)更直接地表示意图。 @Arafangion : std::tuple<>也是类型安全的(怎么可能不是?),2 在语义上与pair 没有区别。跨度> "因此,std::pair 是一种更准确的使用类型安全的类型" 我想任何说英语的人都会认为“pair”和“two”完全是同义词。 :-] @ildjam:我们在这里分心,但不,它们不是完全的同义词。当您说“两双鞋”时,您的意思是“两双鞋,很可能都是左鞋”,还是“一双鞋”(其中一只总是左,另一只总是右) ?【参考方案3】:

这是一个非常晚的答案,但请注意,由于std::pair 是使用成员变量定义的,因此无法使用empty base class optimization 优化其大小(firstsecond 必须占用不同的地址,即使其中一个或两个都占用是一个空类)。 second_type 的任何对齐要求都会加剧这种情况,因此在最坏的情况下,生成的 std::pair 基本上会是所需大小的两倍。

std::tuple 仅允许通过辅助函数进行访问,因此如果其中一个为空,则它可以从任一类型派生,从而节省开销。至少,GCC 的实现肯定是这样做的……您可以通过标头来验证这一点,但也有 this 作为证据。

【讨论】:

当然C++20 [[no_unique_address]]应该消除std::pair的劣势。 "std::tuple 只允许通过辅助函数访问",或 C++17 结构化绑定。遗憾的是,这些天这么多合理的 C++ 答案很快就过时了。 :-( 想一想,这个答案其实是错误的。考虑一个T,它是空的并且可以简单地复制。最后一个意味着可以从另一个现有的T 转到memcpy。这将复制一个字节,因为空类型的大小为 1。如果您有 tuple<T, int>,如果您获得对 T 的引用,则可以在其上复制一个字节。如果tuple 优化了T 的存储空间,那么它无疑会与int 重叠。因此,复制该字节部分复制了int,从而破坏了它。 基类不会发生这种情况,因为在什么时候可以对对象执行memcpy 的规则中有明确的规定:如果对象是基类就不行类子对象(注意:这在 C++20 中扩展为 no_unique_address 成员子对象)。 tuple 的成员没有这样的例外。【参考方案4】:

请注意,在 C++ 17 中,可以使用相同的接口从具有两个元素的对和元组中读取数据。

auto [a, b] = FunctionToReturnPairOrTuple();

无需使用get<> :)

【讨论】:

【参考方案5】:

不管怎样,我发现 std::tuple 的 GDB 输出更难阅读。显然,如果您需要 2 个以上的值,则 std::pair 将不起作用,但我确实认为这是支持结构的一点。

【讨论】:

这就是为什么当我在课堂上使用它们时,我将粗线 std::get<0>(tupleName) 包装在一个吸气剂中; GetX() 更容易阅读且更短。它有一个小缺点,如果您忘记将其设置为 const 方法,有人可能会做一些愚蠢的事情:GetX() = 20;【参考方案6】:

也许值得注意的是,cppreference 指出:

“一对是具有两个元素的 std::tuple 的特定情况。”

【讨论】:

回顾std::pair's change history 提问时没有出现此文字。历史上最早出现的文字是two years later

以上是关于只有两个成员的 std::pair 和 std::tuple 之间的区别?的主要内容,如果未能解决你的问题,请参考以下文章

如何将两个 std::vector 与 std::pair 组合成一个 std::vector

为啥 std::pair 对于 const 引用和转发引用参数有两个不同的构造函数?

C++ 中的 std::pair 和 std::tuple

C++ 中的 std::pair 和 std::tuple

STL std::pair基本用法

为什么std :: pair类标准被改为禁止在C ++ 11中只有非常量复制构造函数的类型?