web-dev-qa-db-ja.com

std :: Tupleはどのように実装されていますか?

タプルがC++ 0xの標準ライブラリにどのように実装されているのか知りたいのですが。 libstdc ++マニュアルの説明 を読んでから テンプレートリスト を読んでみましたが、特にコードを読むとき、それがどのように機能するかを理解するのは本当に難しいです。

誰かがタプルの実装のアイデアを数文で説明できますか?コードでタプルを使用することを考えており、タプルがどのように機能し、どのような種類のオーバーヘッドが発生するかを理解したいので、これを知りたいです(コンパイル時間のみを延長し、メモリで多くのコピー操作を実行し、コンストラクターで他の多くの関数を実行しますなど)。

28
Goofy

タプルを実装するための1つのアプローチは、多重継承を使用することです。タプル要素はリーフクラスによって保持され、タプルクラス自体は複数のリーフから継承します。擬似コードの場合:

template<typename T0, typename T1, ..., typename Tn>
class PseudoTuple : TupleLeaf<0, T0>, TupleLeaf<1, T1>, ..., TupleLeaf<n, Tn> {
   ...
};

各リーフにはインデックスがあるため、含まれるタイプが同一であっても各基本クラスは一意になるため、nth要素にアクセスできます。単純なstatic_cast:

static_cast<TupleLeaf<0, T0>*>(this);
// ...
static_cast<TupleLeaf<n, Tn>*>(this);

この「フラットな」タプル実装についての詳細な説明をここに書きました: C++ 11タプル実装の詳細(パート1)

26
mitchnull

タプルは通常、コンパイル時のリンクリストとして実装されます。

コードはtemplate-syntaxによって少し難読化されていますが、通常は次の要素が存在します。

  1. 頭と尾の要素(短所-要素)を持つクラスのチェーン
  2. リストの終わりを示す空のテールインスタンス。
  3. リストを特定のインデックスに移動する再帰コード。再帰テンプレートインスタンス化(コンパイル時にインスタンス化)として実装されます。

C++ 03には妥当な実装があります(例:ブースト)。

Mottiが述べたように、可変個引数テンプレートでは要素の数に制限はありません。

コストは通常​​、コンパイル時間1です。コピーコンストラクタは、初期化中(最大1)、およびタプル自体をコピーするときに呼び出される場合があります。

10
mirk

参照用に非擬似コードの単純な再帰的実装を追加すると思いました

#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;
}
6
Andrea Allais

std::Tupleの実装は、コア言語に導入された 可変個引数テンプレート を介して可能です。

私はこれが論点先取であることを知っていますが、それはあなたに研究するためのより良い検索フレーズを与えます。

3
Motti