Search code examples
c++c++17variadic-templatestemplate-meta-programming

Slice integer parameter pack


I have a class that gets an integer parameter pack [a,b,...,y,z]. I need to expand it into two packs [a,...,y] and [b,...,z] - that is remove once the first and once the last. The end product is supposed to be a bunch of 2-d arrays sized [a,b],[b,c], etc. until [x,y],[y,z]. I am trying to use something like this:

std::tuple< std::array< std::array< int, /*RemoveFirst*/Ints>, /*RemoveLast*/Ints>...>

I am open to other solutions, too.

Example:

template <int... Ints>
struct S {
  std::tuple< std::array< std::array< int, /*RemoveFirst*/Ints>, /*RemoveLast*/Ints>...> t;
};
int main() {
  S<2,3,4> a;
  std::get<0>(a.t)[0][0] = 42;
  // explenation:
  // a.t               is tuple<array<array<int,3>,2>,array<array<int,4>,3>>
  // get<0>(a.t)       is array<array<int,3>,2>
  // get<0>(a.t)[0]    is array<int,3>
  // get<0>(a.t)[0][0] is int
}

Solution

  • I propose the following code

    #include <array>
    #include <tuple>
    #include <utility>
    #include <type_traits>
    
    template <typename T, std::size_t ... Is>
    auto constexpr bar (std::index_sequence<Is...> const &)
     { return
          std::tuple<
             std::array<
                std::array<int,
                           std::tuple_element_t<Is+1u, T>::value>,
                std::tuple_element_t<Is, T>::value>...
          >{}; }
    
    template <std::size_t ... Is>
    auto constexpr foo ()
     { return bar<std::tuple<std::integral_constant<std::size_t, Is>...>>
                 (std::make_index_sequence<sizeof...(Is)-1u>{}); }
    
    int main ()
     {
       constexpr auto f = foo<2u, 3u, 5u, 7u, 11u>();
    
       using typeTuple = std::tuple<
          std::array<std::array<int, 3u>, 2u>,
          std::array<std::array<int, 5u>, 3u>,
          std::array<std::array<int, 7u>, 5u>,
          std::array<std::array<int, 11u>, 7u>>;
    
       static_assert( std::is_same<typeTuple const, decltype(f)>::value, "!" );
     }