Parameter pack must be at the end of the parameter list... When and why?
It is valid for function templates but only when argument deduction can help the compiler resolve the template parameters, as it stands your function template example is virtually useless because
template<typename T, typename... Args, typename S> void fn() { }
int main() { fn<int, int, int>(); }
test.cpp: In function 'int main()':
test.cpp:2:32: error: no matching function for call to 'fn()'
int main() { fn<int, int, int>(); }
^
test.cpp:1:57: note: candidate: template<class T, class ... Args, class S> void fn()
template<typename T, typename... Args, typename S> void fn() { }
^
test.cpp:1:57: note: template argument deduction/substitution failed:
test.cpp:2:32: note: couldn't deduce template parameter 'S'
int main() { fn<int, int, int>(); }
the compiler has no way of determining which template parameters belong to the parameter pack, and which to S
. In fact as @T.C. points out it should actually be a syntax error because a function template defined in this manner cannot ever be instantiated.
A more useful function template would be something like
template<typename T, typename... Args, typename S> void fn(S s) { }
as now the compiler is able to unambiguously match the function parameter s
with the template type S
, with the side effect that S
will always be deduced - all explicit template parameters after the first will belong to Args
.
None of this works for (primary) class templates, parameters aren't deduced and it's expressly forbidden:
From draft n4567
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf
[temp.param] / 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.[...]
(if they were deduced it would be ambiguous as in the function template example).
Why must the template parameter pack be last?
The variable template declaration is ill-formed, and it's a gcc bug for not diagnosing it.
From temp.param#14:
... If a template-parameter of a primary class template, primary variable template, or alias template is a template parameter pack, it shall be the last template-parameter. ...
The function template is fine, since the rules for function templates are different. If the template parameters after the parameter pack can be deduced by the arguments provided at the call site, then the template is ok.
Why am I getting the error parameter pack 'F' must be at the end of the template parameter list
You have another parameter, T
, at the end of the list after F
. As the error message says, the variadic pack must come at the end. Unfortunately, that makes it awkward to have both variadic and defaulted parameters in the same template.
Function template parameter pack not at the end of the parameter list
The interesting part from Clang's error message is:
main.cpp:11:6: note: candidate template ignored: couldn't infer template argument 'T'
void foo(Args... args, T x) {
^
The problem is that the parameter pack Args...
occurs prior to T
.
Args...
is "greedy" and so no parameters are left for the compiler to deduce T
, hence it fails.
Quoting the standard (emphasis mine):
[temp.param]/11
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. [Example:...
// U can be neither deduced from the parameter-type-list nor specified
template<class... T, class... U> void f() { } // error
template<class... T, class U> void g() { } // error
— end example]
Error with variadiac template: parameter pack must be expanded
The error is due to the missing ellipsis (...
) after args
when passing all individual parameters (rather than the parameter pack) to emplace_back
.
The fixed (and improved) version:
template<class Container, class... Args>
auto insert(Container& c, Args&&... args) -> decltype (c.back()) {
c.emplace_back(std::forward<Args>(args)...);
return c.back();
}
Issue with variadic template template parameter pack
int B
is a non-type template parameter. You have to declare Templates
as template<class, auto, class> class
if you want it to work with that particular class template, or redefine Obj
to take a std::integral_constant
to pass a value encapsulated in a type:
template<class A, class B, class C>
struct Obj {
A a_obj;
static constexpr int b_value = B::value;
C c_obj;
};
template<template<class...> class... Templates>
struct Foo;
template<>
struct Foo<Obj> {
Obj<void*, std::integral_constant<int, 5>, float> obj;
};
int main() {
Foo<Obj> foo;
}
Try it on godbolt.org.
Do Variadic Template Parameters Always Have to be Last?
Variardic arguments don't have to be last -- but it doesn't help you.
Your error is in the recursive call, when you try to set begin
to be something different than 0
. In that line, the compiler cannot figure out that your begin
is supposed to be the std::size_t
parameter, and bails out.
This compiles fine even in gcc 5.1:
template <class... Tp, std::size_t begin = 0U>
auto foo(std::tuple<Tp...>& t) -> std::enable_if_t<begin == sizeof...(Tp), void> {
std::cout << '\n';
}
template <class... Tp, std::size_t begin = 0U>
auto foo(std::tuple<Tp...>& t) -> std::enable_if_t<begin < sizeof...(Tp), void> {
std::cout << '\n';
}
(I rewrote it to figure out where it was going wrong, so it is slightly different in unimportant ways).
The important way it differs it the lack of recursive call.
As an aside, your printing code is a bit awkward. Consider using something like for_each_arg
:
template<class F, class...Args>
void for_each_arg(F&& f, Args&&...args) {
using discard=int[];
(void)discard{((
f(std::forward<Args>(args))
),void(),0)...,0};
}
either mix the above with std::apply
or write your own:
namespace details {
template<class F, class Tuple, std::size_t...Is>
decltype(auto) apply( std::index_sequence<Is...>, F&& f, Tuple&& args )
{
return std::forward<F>(f)( std::get<Is>(std::forward<Tuple>(args))... );
}
}
template<class F, class Tuple>
decltype(auto) apply(F&& f, Tuple&& tuple) {
using dTuple = std::decay_t<Tuple>;
return details::apply(
std::make_index_sequence<std::tuple_size<dTuple>::value>{},
std::forward<F>(f),
std::forward<Tuple>(tuple)
);
}
template<class F, class Tuple>
decltype(auto) for_each_tuple_element( F&& f, Tuple&& tuple ) {
return apply(
[&](auto&&...args){
for_each_arg( std::forward<F>(f), decltype(args)(args)... );
},
std::forward<Tuple>(tuple)
);
}
and now you don't have a recursion depth equal to the number of elements in your tuple.
template <class Tuple>
void foo(Tuple&& tuple) {
for_each_tuple_element(
[](auto&& arg){ std::cout << decltype(arg)(arg); },
std::forward<Tuple>(tuple)
);
std::cout << '\n';
}
live example.
template function parameter pack not at the end of the list
Variadic template arguments are greedy, so if you try and explicitly specify the template arguments for a template that has a variadic argument, once the explicit arguments start being allocated to the variadic pack, all remaining arguments are allocated to that pack. In this case A2
is not a type, so when the compiler tries to allocate it to the Ts...
pack, it causes an error.
You could overload your template, allowing the enum
to be specified as the first parameter:
template <A a,typename...Ts >
void foo(Ts...ps) { std::cout << sizeof...(ps); }
template <typename...Ts>
void foo(Ts...ps) { foo<A2>(ps...); }
foo<int,int>(1,2); // this compiles
foo<A2,int,int>(1,2); // this compiles
Variadic templates, parameter pack and its discussed ambiguity in a parameter list
In the class template, a prospective template argument list C<a,b,c,d,e,f>
needs to match
template<typename T, typename... A, typename S>
in which ...A is just floating in a parameter list.
But in the specialization, what needs to be matched is not the list of template variabled but rather the pattern:
C<T(A...), S>
which is easy because the A...
is delimited.
So in the template specialization, the list of parameters is just an inventory of symbols, some scalar and some parameter packs, which will appear in a pattern.
Multiple Variadic Parameter Pack for Template Class
In the discussion comments you expressed a willingness to consider some kind of indirection, or "a wrapper of some kind for the attribute list".
A lightweight std::tuple
-based wrapper, together with specialization, might work here:
template <typename attribute_tuple, APITypes APIType,
typename policy_tuple> class IShader;
template <AttributeType... Attributes, APITypes APIType,
class... Policies>
class IShader<std::tuple<Attributes...>, APIType,
std::tuple<Policies...>> : public Policies... {
// ...
};
The goal here is to use a template instance along the lines of:
IShared<std::tuple<Attribute1, Attribute2>, APITypeFoo,
std::tuple<Policy1, Policy2>> ishared_instance;
And cross your fingers that this is going to match the specialized template declaration, at which point both parameter packs are available for the template specialization to use, individually.
Related Topics
Compiling a Static Executable with Cmake
Compile Time Sizeof_Array Without Using a MACro
Difference Between <String> and <String.H>
How Is C++ Std::Vector Implemented
Tmp: How to Generalize a Cartesian Product of Vectors
Destructors of Builtin Types (Int, Char etc..)
How to Set the Stacksize with C++11 Std::Thread
The Reason of Using 'Std::Greater' for Creating Min Heap via 'Priority_Queue'
In What Ways Do C++ Exceptions Slow Down Code When There Are No Exceptions Thown
Removing a Non Empty Directory Programmatically in C or C++
Are Move Constructors Produced Automatically
Prevent User Process from Being Killed with "End Process" from Process Explorer