#include<iostream>
using namespace std;
template<typename ...Args>
void output_argus(Args&&... args)
{
((cout << args << '\n'), ...); // #1
(... , (cout << args << '\n')); // #2
}
int main()
{
output_argus(1, "test", 5.6f);
}
Based on c++ operator doc, ','
is a left to right operator. It is meaning a, b, c, d
meaning (((a, b), c),d)
not (a, (b, (c, d)))
. This is important if a, b, c, d are statements.
However, based on fold expression doc, for ','
which should use unary left fold.
My question why both statements in my code are working? Shouldn't only #2 work?
And also how to understand ...
and args
. and nested fold expression?
Let's say we're folding 3 expressions over a binary operator, with a unary fold. We have two options here: (xs @ ...)
(a unary right fold) and (... @ xs)
(a unary left fold).
(xs @ ...)
expands out to (a @ (b @ c))
(... @ xs)
expands out to ((a @ b) @ c)
What can we say about the difference between the expressions a @ (b @ c)
and (a @ b) @ c
? If @
is associative over these types, then those two expressions are identical. That's what associative means. If you had a parameter pack of integers, then a unary left fold over +
and a unary right fold over +
will have the same value (modulo overflow), because addition is associative. Subtraction, on the other hand, is not associative. (xs - ...)
and (... - xs)
mean very different things.
Likewise, the ,
operator in C++ is associative. It doesn't matter which way you parenthesize the expressions. ((a, b), c)
and (a, (b, c))
both evaluate and discard a
, then evaluate and discard b
, then evaluate c
and that's the result. It's easier to see if you reduce the expressions to just letters why this is the case.
As a result, both ((cout << args << '\n'), ...)
and (... , (cout << args << '\n'))
do the same thing, and they both effectively mean:
cout << args1 << '\n';
cout << args2 << '\n';
// ...
cout << argsN << '\n';