std :: tuple是如何实现的?

Goo*_*ofy 26 c++ tuples std c++11

我想知道在C++ 0x的标准库中如何实现元组.我试着阅读libstdc ++手册中的描述,然后阅读模板列表,但是很难理解它是如何工作的,特别是在阅读代码时.

有人能用几句话解释我的元组实现的想法吗?我想知道这一点,因为我想在我的代码中使用元组,我想了解它是如何工作的以及它带来了什么类型的开销(仅扩展编译时间,对内存执行许多复制操作,在构造函数中执行许多其他函数)等).

mit*_*ull 27

实现元组的一种方法是使用多重继承.元组元素由叶类保存,元组类本身继承自多个叶子.在伪代码中:

template<typename T0, typename T1, ..., typename Tn>
class PseudoTuple : TupleLeaf<0, T0>, TupleLeaf<1, T1>, ..., TupleLeaf<n, Tn> {
   ...
};
Run Code Online (Sandbox Code Playgroud)

每个叶子都有一个索引,因此即使它们包含的类型相同,每个基类也会变得唯一,所以我们可以使用简单的static_cast 访问第n个元素:

static_cast<TupleLeaf<0, T0>*>(this);
// ...
static_cast<TupleLeaf<n, Tn>*>(this);
Run Code Online (Sandbox Code Playgroud)

我在这里写了关于这个"扁平"元组实现的详细解释:C++ 11元组实现细节(第1部分)

  • @KyleStrand呃,这个_is_非递归实现(T:L1,L2,L3与T:L1:L2:L3的递归实现) (2认同)

mir*_*irk 11

元组通常实现为编译时链接列表.

代码通过模板语法有点混淆,但通常存在以下元素:

  1. 一系列具有头部和尾部元素的类(cons-elements)
  2. 一个空尾实例,用于指示列表的结尾.
  3. 将列表移动到某个索引的递归代码,实现为递归模板实例化(在编译时实例化).

在C++ 03中存在合理的实现(例如,boost).

如Motti所述,可变参数模板允许无限数量的元素.

成本通常是编译时间一.在初始化期间(最大1)可以调用复制构造函数,并且在复制元组本身时也可以调用复制构造函数.


And*_*ais 7

我以为我会添加一个非伪代码的简单递归实现以供参考

#include <iostream>

// Contains the actual value for one item in the tuple. The 
// template parameter `i` allows the
// `Get` function to find the value in O(1) time
template<std::size_t i, typename Item>
struct TupleLeaf {
    Item value;
};

// TupleImpl is a proxy for the final class that has an extra 
// template parameter `i`.
template<std::size_t i, typename... Items>
struct TupleImpl;

// Base case: empty tuple
template<std::size_t i>
struct TupleImpl<i>{};

// Recursive specialization
template<std::size_t i, typename HeadItem, typename... TailItems>
struct TupleImpl<i, HeadItem, TailItems...> :
    public TupleLeaf<i, HeadItem>, // This adds a `value` member of type HeadItem
    public TupleImpl<i + 1, TailItems...> // This recurses
    {};

// Obtain a reference to i-th item in a tuple
template<std::size_t i, typename HeadItem, typename... TailItems>
HeadItem& Get(TupleImpl<i, HeadItem, TailItems...>& tuple) {
    // Fully qualified name for the member, to find the right one 
    // (they are all called `value`).
    return tuple.TupleLeaf<i, HeadItem>::value;
}

// Templated alias to avoid having to specify `i = 0`
template<typename... Items>
using Tuple = TupleImpl<0, Items...>;

int main(int argc, char** argv) {
    Tuple<int, float, std::string> tuple;
    Get<0>(tuple) = 5;
    Get<1>(tuple) = 8.3;
    Get<2>(tuple) = "Foo";
    std::cout << Get<0>(tuple) << std::endl;
    std::cout << Get<1>(tuple) << std::endl;
    std::cout << Get<2>(tuple) << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)