icon-cookie
The website uses cookies to optimize your user experience. Using this website grants us the permission to collect certain information essential to the provision of our services to you, but you may change the cookie settings within your browser any time you wish. Learn more
I agree
blank_error__heading
blank_error__body
Text direction?

How does folding over comma work?

Asked
Active 3 years ago
Viewed 2k times
6

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?

Snps
12.9k55 gold badges4646 silver badges7070 bronze badges
asked Aug 10 '17 at 2:34
Candy ChiuCandy Chiu
6,21777 gold badges4242 silver badges6464 bronze badges
11

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
BarryBarry
231k2525 gold badges441441 silver badges754754 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.

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