std::make_index_sequence 和 std::index_sequence 的细节
我很喜欢使用可变参数模板,并开始摆弄这个新功能.我试图了解 std::index_sequence 的实现细节(用于元组实现).我在那里看到了示例代码,但我真的想要一步一步地解释 std::index_sequence 是如何编码的,以及每个阶段有问题的元编程原理.想想真的愚蠢的:)
I'm enjoying ramping up on variadic templates and have started fiddling about with this new feature. I'm trying to get my head around the implementation details of std::index_sequence's (used for tuple implementation). I see sample code around there, but I really want a dumbed down step by step explanation of how an std::index_sequence is coded and the meta programming principal in question for each stage. Think really dumbed down :)
推荐答案
我在那里看到了示例代码,但我真的想要一步一步地解释 index_sequence 是如何编码的,以及每个阶段的元编程原理.
I see sample code around there, but I really want a dumbed down step by step explanation of how an index_sequence is coded and the meta programming principal in question for each stage.
你问的东西解释起来并不简单......
What you ask isn't exactly trivial to explain...
嗯... std::index_sequence 本身很简单:定义如下
Well... std::index_sequence itself is very simple: is defined as follows
template<std::size_t... Ints>
using index_sequence = std::integer_sequence<std::size_t, Ints...>;
实质上是一个无符号整数的模板容器.
that, substantially, is a template container for unsigned integer.
棘手的部分是 std::make_index_sequence 的实现.也就是说:棘手的部分是从 std::make_index_sequence 传递到 std::index_sequence<0, 1, 2, ..., N-1>.
The tricky part is the implementation of std::make_index_sequence. That is: the tricky part is pass from std::make_index_sequence<N> to std::index_sequence<0, 1, 2, ..., N-1>.
我建议您一个可能的实现(不是一个很好的实现,但简单(我希望)理解),我将尝试解释它是如何工作的.
I propose you a possible implementation (not a great implementation but simple (I hope) to understand) and I'll try to explain how it works.
不完全是从 std::integer_sequence 传递过来的标准索引序列,但是修复 std::size_t 类型你可以获得一个合理的 indexSequence/makeIndexSequence 与以下代码配对.
Non exactly the standard index sequence, that pass from std::integer_sequence, but fixing the std::size_t type you can get a reasonable indexSequence/makeIndexSequence pair with the following code.
// 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;
我想理解它是如何工作的一个好方法是跟随一个实际的例子.
I suppose that a good way to understand how it works is follows a practical example.
我们可以点对点地看到 makeIndexSequence<3> 如何变成 index_sequenxe<0, 1, 2>.
We can see, point to point, how makeIndexSequence<3> become index_sequenxe<0, 1, 2>.
我们将
makeIndexSequence<3>定义为typename indexSequenceHelper<3>::type[N是>3]
We have that
makeIndexSequence<3>is defined astypename indexSequenceHelper<3>::type[Nis3]
indexSequenceHelper<3> 仅匹配一般情况,因此继承自 indexSequenceHelper<2, 2> [N 是 3 和 Next... 为空]
indexSequenceHelper<3> match only the general case so inherit from indexSequenceHelper<2, 2> [N is 3 and Next... is empty]
indexSequenceHelper<2, 2> 只匹配一般情况,因此继承自 indexSequenceHelper<1, 1, 2> [N> 是 2 和 Next... 是 2]
indexSequenceHelper<2, 2> match only the general case so inherit from indexSequenceHelper<1, 1, 2> [N is 2 and Next... is 2]
indexSequenceHelper<1, 1, 2> 仅匹配一般情况,因此继承自 indexSequenceHelper<0, 0, 1, 2> [N 是 1 和 Next... 是 1, 2]
indexSequenceHelper<1, 1, 2> match only the general case so inherit from indexSequenceHelper<0, 0, 1, 2> [N is 1 and Next... is 1, 2]
indexSequenceHelper<0, 0, 1, 2> 匹配这两种情况(一般为部分特化),因此应用部分特化并定义 type = indexSequence<0, 1, 2> [Next... 是 0, 1, 2]
indexSequenceHelper<0, 0, 1, 2> match both cases (general an partial specialization) so the partial specialization is applied and define 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 开始可用
std::index_sequenceandstd::make_index_sequenceare available starting from C++14
我的示例很简单(我希望)易于理解,但是(正如 aschepler 所指出的)具有很大的限制,即线性实现;我的意思是:如果你需要 index_sequence<0, 1, ... 999>,使用 makeIndexSequence<1000> 你可以递归地实现 1000 个不同的 indexSequenceHelper;但是有一个递归限制(编译器形式编译器不同)可以小于 1000;还有其他算法可以限制递归次数,但解释起来更复杂.
my example is simple (I hope) to understand but (as pointed by aschepler) has the great limit that is a linear implementation; I mean: if you need index_sequence<0, 1, ... 999>, using makeIndexSequence<1000> you implement, in a recursive way, 1000 different indexSequenceHelper; but there is a recursion limit (compiler form compiler different) that can be less than 1000; there are other algorithms that limits the number of recursions but are more complicated to explain.
相关文章