Jes
Jes

Reputation: 2684

Implement C++ template for generating an index sequence with a given range

So, C++14 provides struct make_index_sequence<N> for generating an index sequence from 0 to N-1. I am wondering how to implement one to generate an index sequence in a given range. For example:

template <size_t Min, size_t Max>
struct make_index_range;  

// make_index_range<5, 9> will give index_sequence<5, 6, 7, 8>

Upvotes: 4

Views: 1469

Answers (3)

PavelDev
PavelDev

Reputation: 673

The answer, which uses C++20, given by @edrezen can be written more briefly

#include <utility>
#include <iostream>

template<typename T, T Min, T Max>
constexpr auto make_integer_range ()
{
    static_assert (Max>=Min);
    return [] <T... Is> (std::integer_sequence<T,Is...>)
    {
        return std::integer_sequence<T, Is+Min...>{};
    }(std::make_integer_sequence<T, Max-Min+1>{});
}

// integer sequence of -1,0,1,2,3
constexpr auto myrange = make_integer_range<int,-1,3> (); 

// debugging aid (https://en.cppreference.com/w/cpp/utility/integer_sequence)
template<typename T, T... ints>
void print_sequence(std::integer_sequence<T, ints...> int_seq)
{
    std::cout << "The sequence of size " << int_seq.size() << ": ";
    ((std::cout << ints << ' '), ...);
    std::cout << '\n';
}

int main()  {
    print_sequence(myrange);    
}

Upvotes: 0

edrezen
edrezen

Reputation: 1628

I know that the question is tagged with c++14 but it may be interesting to have a version for newer versions of the standard where metaprogramming is a little bit easier (not so obvious in this example though).

Moreover, I also needed to have a range of integers not necessarely bigger than 0, so the following code (for c++20):

#include <numeric>
#include <array>

template<typename T, T Min, T Max>
constexpr auto make_integer_range ()
{
    static_assert (Max>=Min);

    // we create an array filled with the integers from the given [Min,Max] bounds.
    constexpr auto arr = []
    {
        std::array<T, Max-Min+1> a;
        std::iota (a.begin(), a.end(), Min);
        return a;
    } ();

    // we create the integer sequence from the content of the array
    auto build = [&arr] <std::size_t... Is> (std::index_sequence<Is...>)
    {
        return std::integer_sequence<T, arr[Is]...>{};
    };

    return build (std::make_index_sequence<arr.size()>{});
}

// integer sequence of -1,0,1,2,3
constexpr auto myrange = make_integer_range<int,-1,3> (); 

int main()  {}

Upvotes: 0

Jonathan Wakely
Jonathan Wakely

Reputation: 171303

The way you defined index_range (before the question was edited) the answer is simply:

template<std::size_t Min, std::size_t Max>
  using make_index_range = index_range<Min, Max>;

Which is not very useful.

So I'm going to assume you mean make_index_range<5, 9> will give index_sequence<5, 6, 7, 8>, which can be done like this:

#include <utility>

template<std::size_t N, std::size_t... Seq>
  constexpr std::index_sequence<N + Seq ...>
  add(std::index_sequence<Seq...>)
  { return {}; }

template<std::size_t Min, std::size_t Max>
  using make_index_range = decltype(add<Min>(make_index_sequence<Max-Min>()));

Or if you want make_index_range to be a class template, define add as above and then:

template<std::size_t Min, std::size_t Max>
  struct make_index_range {
    using type = decltype(add<Min>(make_index_sequence<Max-Min>()));
  };

(But with this you have to use make_index_range<5, 9>::type so the alias template is probably better, and closer to how make_index_sequence works.)

Upvotes: 12

Related Questions