I was wondering if it\'s possible to write a template function that can take any other arbitrary template as a parameter and properly match the template name (i.e. not just the
Your interesting construct has two levels with variadic templates.
TemplateP
& Sizes
for a function templateTemplateT
, a class templateFirst, let's look at the inner TemplateT
class: why can the ellipsis operator not not match something like TemplateT< int, 2 >
? Well, the standard defines variadic templates in §14.5.3 as
template struct Tuple { };
template struct Tuple2 { };
where the template argument pack in the first case may only match types and in the second version only values of type T
. In particular,
Tuple < 0 > error; // error, 0 is not a type!
Tuple < T, 0 > error2; // T is a type, but zero is not!
Tuple2< T > error3; // error, T is not a value
Tuple2< T, 0 > error4; // error, T is not a value
are all malformed. Furthermore, it is not possible to fall back to something like
template struct Tuple { };
because the standard states in §14.1.11:
If a template-parameter of a primary class template or alias template is a template parameter pack, it shall be the last template-parameter. A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list of the function template or has a default argument (14.8.2).
In other words, for class templates only one variadic parameter pack may appear in the definition. Therefore the above (double)-variadic class definition is malformed. Because the inner class always needs such a combination, it is impossible to write something as general as you conceived.
What can be rescued? For the outer function template, some shards can be put together, but you won't like it. As long as the second parameter pack can be deduced from the first, two parameter packs may appear (in a function template). Therefore, a function such as
template < typename... Args, size_t... N > void g(const std::array< Args, N > &...arr);
g(std::array< double, 3 >(), std::array< int, 5>());
is allowed, because the integer values can be deduced. Of course, this would have to be specialized for every container type and is far from what you had imagined.