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
Xfor 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