整数序列如何展开以生成序列?

时间:2018-09-14 00:29:10

标签: c++ templates c++17 variadic-templates

我有这段代码可以生成1到10的编译时数组

template <int... Is> // when called below, Is will be 0 - N
constexpr std::array<int, sizeof...(Is)>
make_inc_array_impl(std::integer_sequence<int, Is...>) {
    return {{(Is + 1)...}}; // +1 to start at one instead of [0, 1, ...]
}

template <std::size_t N>
constexpr std::array<int, N> make_inc_array() {
    return make_inc_array_impl(std::make_integer_sequence<int, N>{});
}

constexpr auto a = make_inc_array<10>(); // [1, 2, ..., 10]

int main() {
    for(int itr = 0; itr < 10; ++itr)
        printf("%d ", a[itr]);
}

嗯,我对元编程的工作方式有一些经验和知识。但是我仍然不知道这个惊人的例子是如何工作的。

  1. make_inc_array_impl()中,我看到它返回(Is+1)...,那么由于[11, 10, 9, 8, 7, ... 2]的值从Is开始,结果应该是10吗?

  2. 可变参数模板功能make_integer_sequence(parameter pack)如何展开/展开std::integer_sequence<int, Is...>?在正常的元编程中,模板推导从NN-1,直到1递归地工作。但是,为什么它会从1N

您能帮您解释一下背后的原理吗?

1 个答案:

答案 0 :(得分:3)

make_inc_array<10>()的调用返回make_inc_array_impl(std::make_integer_sequence<int, 10>{})std::make_integer_sequence是别名模板。特别是,它被实现为std::make_integer_sequence<int, 10>是类型std::integer_sequence<int, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9>的别名。因此,当使用这种类型的参数调用make_inc_array_impl时,为了使参数类型Is...等于参数类型,推论0 1 2 3 4 5 6 7 8 9std::integer_sequence<int, Is...>。最后,此包在make_inc_array_impl的正文中进行了扩展。包扩展按顺序发生,因此变成0 + 11 + 1,...,9 + 1

其中最棘手的部分是std::make_integer_sequence。如何将其扩展为具有所需的实际连续整数的std::integer_sequence专长?好吧,这已插入到标准库中,因此您不必自己记住如何做,但是如果您想查看答案,请看here

通常需要一个辅助函数,该辅助函数将以std::make_integer_sequence<int, N>{}的结果进行调用,以便有一个位置可以将各个整数放在包{{1 }}。现在,您已经知道了这一技巧,您将开始看到许多可以使用它的地方。