How does the following line unfold?
template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
(void(os << args), ...);
}
Applying the rule,
Unary right fold (E op ...) becomes E1 op (... op (EN-1 op EN))
provided by cppreference,
E = void(os << args)
op = ,
Then the expansion becomes
void(os << args[0], ..., (args[N-3], (args[N-2], args[N-1])) )
?
How about
v.push_back(args), ...
Does it become
v.push_back(args[0], (args[1], ..., (args[N-2], args[N-1])))
Both the expansion and the parenthesis are confusing. Would someone explain?
A fold expression is an instruction for the compiler to repeat the application of an operator over a variadic template pack.
In the C and C++ programming languages, the comma operator (represented by the token , ) is a binary operator that evaluates its first operand and discards the result, and then evaluates the second operand and returns this value (and type); there is a sequence point between these evaluations.
You have to unpack the entire expression that contains the parameter pack. Not just the parameter pack. Just following the rules:
Unary right fold (E op ...) becomes E1 op (... op (EN-1 op EN))
You're right that op
is ,
and E
is void(os << args)
, where args
is the pack, but Ei isn't just argsi, it's the whole expression void(os << args#i)
. So:
(void(os << args), ...);
becomes (using []
for convenience):
void(os << args[0]), void(os << args[1]), void(os << args[2]), ..., void(os << args[N-1]);
which is equivalent to:
os << args[0];
os << args[1];
...
os << args[N-1];
Similarly, (v.push_back(args), ...)
(the parentheses are required) would expand as:
v.push_back(args[0]), v.push_back(args[1]), ..., v.push_back(args[N-1]);
Note that you could also write this example as a binary left fold:
(os << ... << args);
which would expand as:
((((os << args[0]) << args[1]) ... ) << args[N-1]);
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