web-dev-qa-db-ja.com

std :: make_index_sequenceおよびstd :: index_sequenceの詳細

私は可変テンプレートを使いこなして楽しんでおり、この新しい機能をいじり始めました。 std::index_sequenceの実装の詳細(Tupleの実装に使用)を理解しようとしています。そこにサンプルコードがありますが、std::index_sequenceがどのようにコーディングされているか、各段階で問題のメタプログラミングプリンシパルについて、段階を追った説明が本当に必要です。考えてください本当に馬鹿げた:)

12
user3613174

そこにサンプルコードがありますが、index_sequenceのコーディング方法と各ステージの問題のメタプログラミングプリンシパルについて、段階を追った説明が本当に必要です。

あなたが尋ねることは説明するのは簡単ではありません...

さて... std::index_sequence自体は非常に単純です。次のように定義されます

template<std::size_t... Ints>
using index_sequence = std::integer_sequence<std::size_t, Ints...>;

これは、実質的に、符号なし整数のテンプレートコンテナです。

トリッキーな部分は、std::make_index_sequenceの実装です。つまり、トリッキーな部分はstd::make_index_sequence<N>からstd::index_sequence<0, 1, 2, ..., N-1>に渡すことです。

私はあなたに可能な実装を提案します(素晴らしい実装ではありませんが、理解するのは簡単です(私は願っています))。

std::integer_sequenceから渡される正確な標準インデックスシーケンスではありませんが、std::size_tタイプを修正すると、次のコードでindexSequence/makeIndexSequenceの適切なペアを取得できます。

// index sequence only
template <std::size_t ...>
struct indexSequence
 { };

template <std::size_t N, std::size_t ... Next>
struct indexSequenceHelper : public indexSequenceHelper<N-1U, N-1U, Next...>
 { };

template <std::size_t ... Next>
struct indexSequenceHelper<0U, Next ... >
 { using type = indexSequence<Next ... >; };

template <std::size_t N>
using makeIndexSequence = typename indexSequenceHelper<N>::type;

私はそれがどのように機能するかを理解する良い方法は実用的な例に従うと思います。

ポイントツーポイントで、makeIndexSequence<3>index_sequenxe<0, 1, 2>になる方法を確認できます。

  • makeIndexSequence<3>typename indexSequenceHelper<3>::type [N is 3]と定義されています

  • indexSequenceHelper<3>は一般的な場合にのみ一致するため、indexSequenceHelper<2, 2> [N3で、Next...は空から継承します]

  • indexSequenceHelper<2, 2>は一般的な場合にのみ一致するため、indexSequenceHelper<1, 1, 2> [N2で、Next...2]から継承します

  • indexSequenceHelper<1, 1, 2>は一般的な場合にのみ一致するため、indexSequenceHelper<0, 0, 1, 2> [N1で、Next...1, 2]から継承します

  • indexSequenceHelper<0, 0, 1, 2>は両方のケース(一般的な部分的な特殊化)に一致するため、部分的な特殊化が適用され定義されますtype = indexSequence<0, 1, 2> [Next... is 0, 1, 2]

結論:makeIndexSequence<3>indexSequence<0, 1, 2>です。

お役に立てれば。

---編集---

いくつかの説明:

  • std::index_sequenceおよびstd::make_index_sequenceは、C++ 14以降で使用可能です

  • 私の例は簡単に理解できますが(ascheplerが指摘したように)、線形実装であるという大きな制限があります。つまり、index_sequence<0, 1, ... 999>が必要な場合、makeIndexSequence<1000>を使用して、1000種類のindexSequenceHelper;を再帰的に実装します。ただし、1000未満の再帰制限(コンパイラ形式とは異なるコンパイラ)があります。再帰の数を制限する他のアルゴリズムがありますが、説明するのはより複雑です。

18
max66

完全を期すために、std::make_index_sequenceautoを使用して、テンプレートプログラミングを「通常の」プログラミングにより似たものにするif constexprの最新の実装を追加します。

template <std::size_t... Ns>
struct index_sequence {};

template <std::size_t N, std::size_t... Is>
auto make_index_sequence_impl() {
    // only one branch is considered. The other may be ill-formed
    if constexpr (N == 0) return index_sequence<Is...>(); // end case
    else return make_index_sequence_impl<N-1, N-1, Is...>(); // recursion
}

template <std::size_t N>
using make_index_sequence = std::decay_t<decltype(make_index_sequence_impl<N>())>;

このスタイルのテンプレートプログラミングを使用することを強くお勧めします。

7
papagaga