6

Why comma separated unary left fold produce the same result as the right one?

Live code

template<class ...Args>
void right_fold(Args... args){
    ((std::cout << args),...);
}

template<class ...Args>
void left_fold(Args... args){
    (...,(std::cout << args));
}

int main()
{
    right_fold(1,2,3,4);
    std::cout << std::endl;
    left_fold(1,2,3,4);
}

OUTPUT:

1234
1234

Shouldn't it be:

4321
1234

?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
tower120
  • 5,007
  • 6
  • 40
  • 88
  • 1
    Simply put, recedence and order of evaluation is independent – Passer By Apr 16 '18 at 14:40
  • Possible duplicate of [Operator Precedence vs Order of Evaluation](https://stackoverflow.com/questions/5473107/operator-precedence-vs-order-of-evaluation) – Passer By Apr 16 '18 at 14:42

3 Answers3

11

Left vs right folding is the difference between ((a,b),c) and (a,(b,c)), but they have exactly the same effect when the built-in , operator is used: they first evaluate a, then b and finally c. To see a difference, you'd need to use a type with a custom overloaded , operator.

The syntax may look as if it would reverse the arguments, but no, that won't happen.

  • 1
    Why both `((a,b),c)` and `(a,(b,c))` have the same execution order? – tower120 Apr 16 '18 at 14:26
  • 4
    @tower120 [A pair of expressions separated by a comma is evaluated left-to-right;](http://eel.is/c++draft/expr.comma#1.sentence-2). – Rakete1111 Apr 16 '18 at 14:28
  • 1
    @tower120 The first means "first, evaluate a then b, then, evaluate c". The second means "first, evaluate a, then evaluate b then c". The net effect is the same. –  Apr 16 '18 at 14:29
  • @tower120 What order do you expect in each case and why? – n. m. could be an AI Apr 16 '18 at 14:41
  • So... parentheses don't work with commas?... I expected to see a,b,c order for ((a,b),c) because a,b in the deepest parentheses level, and left to right a then b. And b,c,a for (a,(b,c)) because b,c in the deepest level, left to right b then c. – tower120 Apr 16 '18 at 14:44
  • 1
    @tower120 Parentheses do work, but they never pretty much never specify evaluation order. This is no different from other operators. Given `f() * (g() + h())`, `f`, `g` and `h` may be called in any order. There is no requirement to call `g` and `h` first. –  Apr 16 '18 at 14:46
  • So if not this special rule http://eel.is/c++draft/expr.comma#1.sentence-2 , order of evaluation (in case with comma) would be unspecified / compiler dependent? – tower120 Apr 16 '18 at 15:03
  • 2
    @tower120 Exactly. There are a few operators which force left-to-right evaluation, and those are called out specifically in the standard. As of C++17, there are some operators which force right-to-left evaluation, and those are also called out in the standard. For the other operators, the order is entirely up to the implemention. –  Apr 16 '18 at 15:06
4

These folds respectively expand to:

((std::cout << 1), ((std::cout << 2), ((std::cout << 3), (std::cout << 4))))

... and:

((((std::cout << 1), (std::cout << 2)), (std::cout << 3)), (std::cout << 4))

Despite the flurry of parentheses, they are equivalent in terms of order of execution: left to right.

Quentin
  • 62,093
  • 7
  • 131
  • 191
4

Because they are indeed the same thing:

((std::cout << 1, std::cout << 2), std::cout << 3), std::cout << 4;
std::cout << 1, (std::cout << 2, (std::cout << 3, std::cout << 4));

Both have output 1234.

llllllllll
  • 16,169
  • 4
  • 31
  • 54