Как целочисленная_последовательность раскрывается для создания последовательности? - PullRequest
0 голосов
/ 14 сентября 2018

У меня есть этот код, который генерирует массив времени компиляции от 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. Как функция шаблона Variadic make_integer_sequence(parameter pack) раскрывает / расширяет std::integer_sequence<int, Is...>? В обычном метапрограммировании вычитание шаблона работает рекурсивно с N до N-1, вплоть до 1. Но вот почему оно получается от 1 до N?

Не могли бы вы объяснить, в чем заключается принцип?

1 Ответ

0 голосов
/ 14 сентября 2018

Вызов 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 9, чтобы сделать тип параметра std::integer_sequence<int, Is...> равным типу аргумента. Наконец, этот пакет расширен в теле make_inc_array_impl. Расширение пакета гарантированно происходит по порядку, поэтому оно становится 0 + 1, 1 + 1, ..., 9 + 1.

Самая сложная часть этого - std::make_integer_sequence. Как он расширяется до std::integer_sequence специализации с фактическими желаемыми последовательными целыми числами? Ну, это было вставлено в стандартную библиотеку, так что вам не нужно помнить, как это сделать самостоятельно, но если вы хотите увидеть ответ, посмотрите здесь .

Как правило, вам нужна вспомогательная функция, которая вызывается с результатом std::make_integer_sequence<int, N>{}, чтобы можно было поместить отдельные целые числа в последовательность, , т.е. пакет Is.... Теперь, когда вы знаете об этой уловке, вы начнете видеть множество мест, где вы можете ее использовать.

...