I am new to C++ parameter pack expansion, and I have been confused about the position of ...
(ellipsis) for a long time, eg:
template <typename... Args>
void func(Args&&... args) {
// ...
std::forward<Args>(args)...;
// ...
}
Why isn't there std::forward<Args>(args...)
? What is the rule I should follow?
Check out https://en.cppreference.com/w/cpp/language/parameter_pack, particularly the "Pack expansion" section.
Basically, the "..." in the pack expansion is almost like a macro: it creates more source code, in a way. Whatever is before the "..." just gets repeated for each argument (and the pack-name replaced with said argument), so something like func(args...)
would be expanded as "func(a, b, c)", while func(args)...
would turn into "func(a), func(b), func(c)".
std::forward
just takes one argument and produces one forwarded item: func(std::forward(args)...)
will turn into a list of individual forwards: func(std::forward(a), std::forward(b), std::forward(c))
. So, it takes a list of arguments, and produces a list of forwarded arguments
Grammatically, std::forward<Args>(args)...;
doesn't make sense.
You can only use a pack expansion within parentheses or braces.
If you were to call a function, say foo
, then you would write:
foo(std::forward<Args>(args)...)
This would be a postfix-expression foo(/* ... */)
, which contains an expression-list, which is an initializer-list with a single initializer-clause std::forward<Args>(args)
and a ...
.
In other words, the ...
isn't part of the expression; it's part of the list of expressions.
Therefore, ...
is the "outermost" thing, as it has lower precedence than any expression.
*args...
and args()...
would apply *
and ()
to each argument in args
respectively.
You can think of X...
as an instruction that says:
Do
X
for each element in the pack.
std::forward<Args>(args...)
is wrong because the ...
here applies to the initializer-list of arguments when calling std::forward
, but std::forward
is not a variadic function template.
Instead of forwarding each argument, it attempts to call std::forward
with the whole pack passed in.
See also How would one call std::forward on all arguments in a variadic function?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With