我在那里看到了示例代码,但我真的想要一个简单的逐步解释,说明如何对 index_sequence 进行编码以及每个阶段的元编程原理。
你问的问题并不完全是微不足道的解释......
Well... 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>
to 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>
become index_sequenxe<0, 1, 2>
.
我们有那个makeIndexSequence<3>
定义为typename indexSequenceHelper<3>::type
[N
is 3
]
indexSequenceHelper<3>
仅匹配一般情况,因此继承自indexSequenceHelper<2, 2>
[N
is 3
and Next...
是空的]
indexSequenceHelper<2, 2>
仅匹配一般情况,因此继承自indexSequenceHelper<1, 1, 2>
[N
is 2
and Next...
is 2
]
indexSequenceHelper<1, 1, 2>
仅匹配一般情况,因此继承自indexSequenceHelper<0, 0, 1, 2>
[N
is 1
and Next...
is 1, 2
]
indexSequenceHelper<0, 0, 1, 2>
匹配两种情况(一般是部分特化),因此应用部分特化并定义type = indexSequence<0, 1, 2>
[Next...
is 0, 1, 2
]
结论:makeIndexSequence<3>
is indexSequence<0, 1, 2>
.
希望这可以帮助。
- - 编辑 - -
一些澄清:
std::index_sequence
and std::make_index_sequence
从 C++14 开始可用
我的例子很简单(我希望)易于理解,但是(正如 aschepler 所指出的)线性实现有很大的限制;我的意思是:如果你需要index_sequence<0, 1, ... 999>
, using makeIndexSequence<1000>
你以递归的方式实现了 1000 个不同的indexSequenceHelper
;但有一个递归限制(编译器形式编译器不同),可以小于1000;还有其他限制递归次数的算法,但解释起来更复杂。