Reputation: 4118
I feel a bit uncomfortable at the moment when using parameter packs. I've got a function
template <class ... Args>
void f( int x, Args ... args, int y )
{}
and of course using it like this works:
f( 5, 3 );
I am wondering why the following call fails:
f( 5, 3.f, 3 );
It seems like a straight-forward use of parameter packs to me, but according to the compiler Args
is not expanded.
Of course, I could easily replace f
by:
template <class ... Args>
void f( int x, Args ... args )
{
static_assert( sizeof...( args ) >= 1, ... );
extract y from args ...
}
Questions:
Why can't I use parameter packs like this? It seems like the compiler could easily create the replacement code. Or are there any problems with the replacement f()
above?
What is the best way to deal with this, if the order of the parameters is really important to me? (Think of std::transform
for an arbitrary number of input iterators.)
Why is the usage of parameter packs not forbidden in the situation above? I assume, it is because they could be expanded explicitly, e.g. f<float>( 5, 3.f, 3 )
?
Upvotes: 7
Views: 1585
Reputation: 300139
Why can't I use parameter packs like this? It seems like the compiler could easily create the replacement code. Or are there any problems with the replacement f() above?
Might be easy in this particular case, might not be in others. The real answer is that the Standard specifies the behavior and the Standard did not specify any transformation... and in general rarely does.
I would note that your transformation does not work with SFINAE, since static_assert
are hard-errors, so I am glad the transformation is not performed. (Hint: what if f
is overloaded with a single-argument version taking a float
, which would get chosen with/without transformation for f(1)
?)
What is the best way to deal with this, if the order of the parameters is really important to me? (Think of
std::transform
for an arbitrary number of input iterators.)
Explicitly specifying the template pack parameters.
Why is the usage of parameter packs not forbidden in the situation above? I assume, it is because they could be expanded explicitly, e.g. f( 5, 3.f, 3 )?
I think that your assumption is spot on; if explicitly specified this works as expected.
Upvotes: 2
Reputation: 27577
It's a case of you can have other non-variadic template parameters, but only after these non-variadic arguments have been allocated to the non-variadic parameters, can the remainders constitute the parameter pack for the variadic parameter. So you have to move the int y
at the end of your argument list to before the variadic parameters. Something like:
template <class... Args>
void f(int x, int y, Args... args)
{}
Upvotes: 0