Distribute non-type parameter pack across different template parameter packs

c iterate over parameter pack
parameter packs not expanded with
c++ variadic templates unpack
template template parameter
parameter pack must be expanded in this context
non-type template parameter
variadic template constructor
c variadic function

Is there any syntax through which I can distribute a non-type parameter pack across the parameters of a parameter pack of templates, expecting non-type packs (of different sizes)? Since this is pretty confusing I believe that an example may help to clarify what I mean: https://godbolt.org/z/FaEGTV

template <typename T, int... I> struct Vec { };

struct A
{
    template<template<typename, int...> typename...  Container,
        typename... Ts, int... Is>
    A(Container<Ts,Is...>... );
};  

A a(Vec<int, 0>{}, Vec<double, 0>{});       // ok
A b(Vec<int, 0, 1>{}, Vec<double, 0, 1>{}); // ok
A c(Vec<int, 0>{}, Vec<double, 0, 1>{});    // error

I want the line marked // error to work with a syntax similar to what I have. Clearly it will work fine if I write a special constructor to handle this case. However I want this to work for any number of containers, without me having to spell it out explicitly for all possible cases. For example, if I have 2 containers a,b, with index sets {0,1,2} and {0,1,2,3} the expansion should look like A(a[0],a[1],a[2], b[0],b[1],b[2],b[3]).

I am aware that I could do this recursively, unpacking one container at a time, and delegating recursively to constructors expecting a sequence of only flat elements in the beginning. My question is whether this is feasible in a more elegant, efficient, and less verbose way.


For example, if I have 2 containers a,b, with index sets {0,1,2} and {0,1,2,3} the expansion should look like A(a[0],a[1],a[2], b[0],b[1],b[2],b[3]).

I am aware that I could do this recursively, unpacking one container at a time, and delegating recursively to constructors expecting a sequence of only flat elements in the beginning. My question is whether this is feasible in a more elegant, efficient, and less verbose way.

Do you accept a solution where the expansion give you a std::tuple with a[0],a[1],a[2], b[0],b[1],b[2],b[3] ?

In this case, you can follows the Igor's suggestion, unpack the values in the containers and repack they in tuples and use std::tuple_cat() to concatenate the tuples.

I mean... given a container/tuple converter as follows

template <template<typename, std::size_t...> typename C,
          typename T, std::size_t... Is>
auto getTpl (C<T, Is...> const & v)
 { return std::make_tuple(v.data[Is]...); } 

you can start write your constructor, calling a delegate constructor, as follows

   template <typename ... Ts>
   A (Ts const & ... ts) : A{ std::tuple_cat( getTpl(ts)... ) }
    { } 

and the final constructor is

   template <typename ... Ts>
   A (std::tuple<Ts...> const & tpl)
    { /* do something with values inside tpl */ }

The following is a full compiling example

#include <iostream>
#include <string>
#include <tuple>

template <typename T, std::size_t ... Is>
struct Vec
 {
   T data [sizeof...(Is)] = { Is... };

   T const & operator[] (std::size_t i) const
    { return data[i]; }

   T & operator[] (std::size_t i)
    { return data[i]; }
 };

template <template<typename, std::size_t...> typename C,
          typename T, std::size_t... Is>
auto getTpl (C<T, Is...> const & v)
 { return std::make_tuple(v.data[Is]...); }

struct A
 {
   template <typename ... Ts>
   A (std::tuple<Ts...> const & tpl)
    { /* do something with values inside tpl */ }

   template <typename ... Ts>
   A (Ts const & ... ts) : A{ std::tuple_cat( getTpl(ts)... ) }
    { } 
 };  

int main ()
 {
   A a(Vec<int, 0>{}, Vec<double, 0>{});       // ok
   A b(Vec<int, 0, 1>{}, Vec<double, 0, 1>{}); // ok
   A c(Vec<int, 0>{}, Vec<double, 0, 1>{});    // ok, now
 }

Parameter pack(since C++11), Template parameter pack (appears in alias template, class template, variable template and function 1) A non-type template parameter pack with an optional name error: pack expansion contains parameter packs of different lengths. How to write declaration that will accept arbitrary number of parameters of the same type? There are many ways but, IMHO, with drawbacks. A possible way is the use of SFINAE: you can impose that the variadic types are equal to the first type. The following is a C++17 possible solution that uses template folding. template <typename T, typename


I would simply do:

template <typename T>
struct is_container_type : std::false_type{};

template<template<typename, size_t...> typename  C, typename T, size_t... Is>
struct is_container_type<C<T, Is...>> : std::true_type
{
    // Potential `using` to retrieve C, T, Is...
};

struct A
{
    template<typename...  Cs, REQUIRES(is_container_type<Cs>::value && ...)>
    A(Cs... cs)
    {
        ((void)(std::cout << cs << "\n"), ...);
    }
}; 

Demo

With multi_apply (std::apply version for multiple tuple) (you can found there), you might do:

struct A
{

    template<typename...  Ts, REQUIRES(!is_container_type<Ts>::value || ...)>
    A(Ts... ts)
    {
        ((std::cout << ts << " "), ...);
        std::cout << std::endl;
    }


    template<typename...  Cs, REQUIRES(is_container_type<Cs>::value && ...)>
    A(Cs... cs) :
        A(multiple_apply([](auto...args){ return A(args...); },
                         cs...) // if Cs is tuple-like
                         // as_tuple(cs)...) // convert Cs to tuple<int, /*..*/, int>
          )
    {
    }

}; 

Demo

Efficient parameter pack indexing · Louis Dionne, Recently, I've been looking at ways to index into parameter packs with as little template <std::size_t I, typename T> struct indexed { using type = T; }; way to extract the n-th element of a parameter pack, which is not too difficult: For different values of n , we'll fetch all the elements in a parameter pack of  In this example, the non-type parameter pack A is expanded into a list of zero or more non-type template parameters. In a context where template arguments can be deduced; for example, function templates and class template partial specializations, a template parameter pack does not need to be the last template parameter of a template.


I managed to produce a somewhat inefficient solution, that builds a larger vector in the first argument with every recursive step, and then has also a constructor that accepts a single vector and expands that. Clearly this is not ideal, since N vectors are created with a total number of elements N^2/2 in the worst case. Here is an example implementation illustrating what I did: https://coliru.stacked-crooked.com/a/1f41f3793846cdb1

I tried a different version, where no new objects are constructed, however the compiler didn't manage to deduce the proper constructor for some reason (I supposed it's due to the multiple expansions) - this version is in the GROW_VECTOR 0 define in the example linked above.

unpacking variadic template arguments to define new template , In other words, I have a class template Template parameter pack (appears in alias template, class template, variable calls Class::Class(n, ++E1, ++E2, ++E3); ::new((void *)p) Parameter packs can also be used for non-type parameters. IntellijIndexingStats; 8327 | Sample Distribution Simulation not resulting in Normal. A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments. A template with at least one parameter pack is called a variadic template.


Chapter 23: Advanced Template Use, In addition to template type and template non-type parameters there is a third kind of This is no different for class templates, but only if the compiler can figure out what template <size_t acc, char c> // empty parameter pack struct NM2km< acc, Storage as well as its use is provided in the C++ Annotations's distribution in  A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments. A template with at least one parameter pack is called a variadic template.


C++ Annotations Version 11.4.0, In addition to other constructors a circular queue must offer a constructor Different from function template non-type parameters the values of class Parameter packs can be used to bind type and non-type template arguments to the first template argument of a parameter pack with this additional (first) type parameter. The specified template arguments must match the template parameters in kind (i.e., type for type, non-type for non-type, and template for template). There cannot be more arguments than there are parameters (unless one parameter is a parameter pack, in which case there has to be an argument for each non-pack parameter)


Parameter pack, Template parameter pack (appears in a class template and in a function template parameter list) 1) A non-type template parameter pack with an optional name. 2 ) A type error: pack expansion contains parameter packs of different lengths. Of course, you might need to call methods with just some of the parameters from the parameter pack, or some combination of parameter packs. Once you have the parameters in a std::tuple, you can manipulate that tuple with some more template cleverness. For instance: std::tuple_cat() concatenates two tuples into one.