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

Creating tuple of types derived from Variadic Template Pack


Given a list of size_t values as a variadic template parameter pack, how does one make a tuple of derived types (e.g. Matrix) depending on the parameter pack in such a way, that n-th element of variadic generates Matrix<n, n+1>. For example:

make_matrix_tuple<2,3,4,5>() == make_tuple( Matrix<2,3>, Matrix<3,4>, Matrix<4,5> );

How to write make_matrix_tuple function taking in a parameter pack of size_t?

By a type derived I do not mean inheritance but dependence (?). I'm not sure what the proper term is.
Unpacking parameter pack is simple enough

template <typename ElementType, size_t... Sizes>
void make_tuple_of_vectors() { std::tuple < std::array<ElementType, Sizes> ... > tuple; }

However I believe I am a bit over my head where it comes to the next part. I was trying recursively unpack a pair of arguments from parameter pack like so:

template <typename Type, size_t size1, size_t size2>
struct dummy_matrix
{
    size_t SIZE1 = size1;
    size_t SIZE2 = size2;
    using type = Type;
};

template <size_t Iterator, typename ElementType, size_t T, size_t... Sizes>
struct unpack_two
{
    using type = typename unpack_two<Iterator - 1, ElementType, Sizes...>::type;
};

template<typename ElementType, size_t T, size_t T2, size_t... Sizes>
struct unpack_two<0, ElementType, T, T2, Sizes...>
{ 
    using type = dummy_matrix<ElementType, T, T2>;
};

So that unpack_two<N, Type, Sizes...>::type gives N-th and (N+1)-nth Matrix type.
With that, I'm stuck with something that appears sensible to me, yet the compiler disagrees harshly.

template <size_t... Sizes, size_t... Is>
auto
foo_impl(std::index_sequence<Is...>) {
    std::tuple < unpack_two<Is, float, Sizes ... >::type ... > tuple; 
    return tuple; 
}
template <size_t... Args>
void foo()
{
    auto vs = foo_impl<Args...>(std::make_index_sequence<sizeof...(Args)-1>{});
}
int main() { foo<6,9,12>(); }

I'm trying to unpack list of std::size_t Sizes for the unpack_two template, and then unpack std::index_sequence for the std::make_tuple().
I would appreciate explanations as to why my tries are failing, or even is the std::index_sequence right tool here. But I'm mostly interested in any solution to the posed problem.


Solution

  • how does one make a tuple of derived types (e.g. Matrix) depending on the parameter pack in such a way, that n-th element of variadic generates Matrix<n, n+1> [?]

    Maybe using a constexpr std::array in an helper function?

    An example

    #include <array>
    #include <tuple>
    #include <utility>
    
    template <std::size_t, std::size_t>
    struct Matrix
     { };
    
    template <std::size_t ... Ds, std::size_t ... Is>
    auto mmt_helper (std::index_sequence<Is...>)
     {
       constexpr std::array ca { Ds... };
    
       return std::make_tuple(Matrix<ca[Is], ca[Is+1u]>{}...);
     }
    
    template <std::size_t ... Ds>
    auto make_matrix_tuple ()
     { return mmt_helper<Ds...>(std::make_index_sequence<sizeof...(Ds)-1>{}); }
    
    int main ()
     {
       auto mt = make_matrix_tuple<2,3,4,5>();
    
       using T1 = decltype(mt);
       using T2 = std::tuple<Matrix<2u, 3u>, Matrix<3u, 4u>, Matrix<4u, 5u>>;
    
       static_assert( std::is_same_v<T1, T2> );
     }