Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does folding over comma work?

Tags:

c++

c++17

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?

like image 453
Candy Chiu Avatar asked Aug 10 '17 02:08

Candy Chiu


People also ask

What is fold expression?

A fold expression is an instruction for the compiler to repeat the application of an operator over a variadic template pack.

What is comma C++?

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.


1 Answers

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]);
like image 65
Barry Avatar answered Oct 30 '22 03:10

Barry