The website uses cookies. By using this site, you agree to our use of cookies as described in the Privacy Policy.
I Agree
Text direction?

How does folding over comma work?

Viewed 2k times

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?

12.9k66 gold badges4646 silver badges7070 bronze badges
asked Aug 10 '17 at 2:34
Candy ChiuCandy Chiu
6,22788 gold badges4242 silver badges6464 bronze badges

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]);
answered Aug 10 '17 at 2:42
232k2525 gold badges446446 silver badges758758 bronze badges
  • To be more precise, should the unpacking of the unary case be identical to the binary case with all the parenthesis? (assuming the same unpacking order is applied). – Candy Chiu Aug 10 '17 at 15:12
  • 1
    @Barry did you omit some parenthesis in the unary expansion? void(os << args[0]), (void(os << args[1]), (void(os << args[2]), ... (void(os << args[N-2], void(os << args[N-1]))...)); the parenthesis may be important in other scenarios. – Candy Chiu Aug 11 '17 at 14:56
  • 1
    @CandyChiu Yes, but they're not important in this scenario, so they don't really help in explaining what happens. They're just... more parentheses. – Barry Aug 11 '17 at 15:08
  • 1
    why is casting to void needed? – In78 Jan 21 at 19:07
  • 1
    @Silicomancer All folding requires parentheses, it's part of the grammar. – Barry Mar 21 at 18:37

Your Answer

Sign up or log in

Sign up using Google
Sign up using Facebook
Sign up using Email and Password

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged c++ c++17 or ask your own question.

Related Notes
Get a free MyMarkup account to save this article and view it later on any device.
Create account

End User License Agreement

Summary | 1 Annotation
unpack the entire expression that contains the parameter pack. Not just the parameter pack
2020/09/04 09:38