CodeNebula
C++14stlintermediate

std::integer_sequence / index_sequence / make_index_sequence / index_sequence_for

C++14 · Modern Refined · Compiler flag: -std=c++14

Explanation

`std::integer_sequence<T, Ints...>` represents a compile-time sequence of integers. The aliases `std::index_sequence`, `std::make_index_sequence<N>`, and `std::index_sequence_for<Types...>` provide convenient ways to generate sequences of `std::size_t` values. These are essential building blocks for tuple unpacking, variadic template expansion, and compile-time iteration.

Real-World Scenario

A lightweight dependency-injection framework stores constructor arguments in a tuple and needs to unpack them in order when invoking the constructor. `std::index_sequence` enables the expansion.

Quick Snippet

snippet.cpp
#include <tuple>
#include <iostream>
#include <utility>

template<typename Tuple, std::size_t... Is>
void print_impl(const Tuple& t, std::index_sequence<Is...>) {
    ((std::cout << (Is == 0 ? "" : ", ") << std::get<Is>(t)), ...);
    std::cout << "\n";
}

template<typename... Args>
void print_tuple(const std::tuple<Args...>& t) {
    print_impl(t, std::index_sequence_for<Args...>{});
}

int main() {
    auto data = std::make_tuple(42, 3.14, "hello");
    print_tuple(data); // 42, 3.14, hello
}

Full Example

integer_sequence.cpp
// CodeNebula - C++14 Example: std::integer_sequence
// Compile: g++ -std=c++14 -Wall -Wextra -o example integer_sequence.cpp

// Demonstrates std::integer_sequence, std::index_sequence, and
// std::make_index_sequence for compile-time index generation. Real-world use:
// unpacking tuples into function arguments, compile-time array manipulation,
// and variadic template parameter pack indexing.

#include <iostream>
#include <tuple>
#include <array>
#include <utility>
#include <string>

// ------------------------------------------------------------------
// 1. Print all elements of a tuple using index_sequence
// ------------------------------------------------------------------
template<typename Tuple, std::size_t... Is>
void print_tuple_impl(const Tuple& t, std::index_sequence<Is...>)
{
    // Fold using initializer list trick (C++14 compatible)
    using swallow = int[];
    (void)swallow{0, (void(std::cout << (Is == 0 ? "" : ", ")
                                     << std::get<Is>(t)), 0)...};
}

template<typename... Args>
void print_tuple(const std::tuple<Args...>& t)
{
    std::cout << "(";
    print_tuple_impl(t, std::make_index_sequence<sizeof...(Args)>{});
    std::cout << ")";
}

// ------------------------------------------------------------------
// 2. Call a function with tuple elements as arguments
// ------------------------------------------------------------------
template<typename F, typename Tuple, std::size_t... Is>
auto apply_impl(F&& f, Tuple&& t, std::index_sequence<Is...>)
{
    return f(std::get<Is>(std::forward<Tuple>(t))...);
}

template<typename F, typename Tuple>
auto apply(F&& f, Tuple&& t)
{
    constexpr auto size = std::tuple_size<typename std::decay<Tuple>::type>::value;
    return apply_impl(std::forward<F>(f), std::forward<Tuple>(t),
                      std::make_index_sequence<size>{});
}

// ------------------------------------------------------------------
// 3. Generate compile-time array with transformed values
// ------------------------------------------------------------------
template<std::size_t... Is>
constexpr auto make_squares(std::index_sequence<Is...>)
{
    return std::array<std::size_t, sizeof...(Is)>{{(Is * Is)...}};
}

template<std::size_t N>
constexpr auto make_squares()
{
    return make_squares(std::make_index_sequence<N>{});
}

// ------------------------------------------------------------------
// 4. Print an integer_sequence's values
// ------------------------------------------------------------------
template<typename T, T... Ints>
void print_sequence(std::integer_sequence<T, Ints...>)
{
    std::cout << "  Sequence:";
    using swallow = int[];
    (void)swallow{0, (void(std::cout << " " << Ints), 0)...};
    std::cout << std::endl;
}

// ------------------------------------------------------------------
// Test function for apply()
// ------------------------------------------------------------------
int sum_three(int a, int b, int c)
{
    return a + b + c;
}

int main()
{
    // ------------------------------------------------------------------
    // 1. Printing integer sequences
    // ------------------------------------------------------------------
    std::cout << "=== Integer Sequences ===" << std::endl;
    print_sequence(std::make_index_sequence<6>{});
    print_sequence(std::integer_sequence<int, 2, 4, 6, 8>{});
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 2. Tuple printing with index_sequence
    // ------------------------------------------------------------------
    auto t1 = std::make_tuple(42, 3.14, std::string("hello"), 'A');

    std::cout << "=== Tuple Printing ===" << std::endl;
    std::cout << "  ";
    print_tuple(t1);
    std::cout << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 3. Apply: unpack tuple into function call
    // ------------------------------------------------------------------
    auto args = std::make_tuple(10, 20, 30);
    int result = apply(sum_three, args);

    std::cout << "=== Apply (Tuple -> Function Args) ===" << std::endl;
    std::cout << "  sum_three(10, 20, 30) = " << result << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. Compile-time array generation
    // ------------------------------------------------------------------
    constexpr auto squares = make_squares<8>();

    std::cout << "=== Compile-Time Squares Array ===" << std::endl;
    std::cout << "  squares[0..7]:";
    for (auto s : squares)
        std::cout << " " << s;
    std::cout << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 5. Size of sequences
    // ------------------------------------------------------------------
    std::cout << "=== Sequence Sizes ===" << std::endl;
    using seq5 = std::make_index_sequence<5>;
    std::cout << "  make_index_sequence<5>::size() = " << seq5::size() << std::endl;
    using seq10 = std::make_index_sequence<10>;
    std::cout << "  make_index_sequence<10>::size() = " << seq10::size() << std::endl;

    return 0;
}

/*
Expected output:

=== Integer Sequences ===
  Sequence: 0 1 2 3 4 5
  Sequence: 2 4 6 8

=== Tuple Printing ===
  (42, 3.14, hello, A)

=== Apply (Tuple -> Function Args) ===
  sum_three(10, 20, 30) = 60

=== Compile-Time Squares Array ===
  squares[0..7]: 0 1 4 9 16 25 36 49

=== Sequence Sizes ===
  make_index_sequence<5>::size() = 5
  make_index_sequence<10>::size() = 10
*/
Run command
g++ -std=c++14 -Wall -Wextra -o example integer_sequence.cpp