私は可変テンプレートを使いこなして楽しんでおり、この新しい機能をいじり始めました。 std::index_sequence
の実装の詳細(Tupleの実装に使用)を理解しようとしています。そこにサンプルコードがありますが、std::index_sequence
がどのようにコーディングされているか、各段階で問題のメタプログラミングプリンシパルについて、段階を追った説明が本当に必要です。考えてください本当に馬鹿げた:)
そこにサンプルコードがありますが、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>
[N
は3
で、Next...
は空から継承します]
indexSequenceHelper<2, 2>
は一般的な場合にのみ一致するため、indexSequenceHelper<1, 1, 2>
[N
は2
で、Next...
は2
]から継承します
indexSequenceHelper<1, 1, 2>
は一般的な場合にのみ一致するため、indexSequenceHelper<0, 0, 1, 2>
[N
は1
で、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未満の再帰制限(コンパイラ形式とは異なるコンパイラ)があります。再帰の数を制限する他のアルゴリズムがありますが、説明するのはより複雑です。
完全を期すために、std::make_index_sequence
とauto
を使用して、テンプレートプログラミングを「通常の」プログラミングにより似たものにする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>())>;
このスタイルのテンプレートプログラミングを使用することを強くお勧めします。