Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't a left fold expression invert the output of a right fold expression?

I'm taking a look at C++17 fold expressions and I'm wondering why does the following program outputs

4 5 6 
4 5 6 

for both of the for_each calls

template<typename F, typename... T>
void for_each1(F fun, T&&... args)
{
    (fun (std::forward<T>(args)), ...);
}

template<typename F, typename... T>
void for_each2(F fun, T&&... args)
{
    (..., fun (std::forward<T>(args)));
}

int main()
{
     for_each1([](auto i) { std::cout << i << std::endl; }, 4, 5, 6);
     std::cout << "-" << std::endl;
     for_each2([](auto i) { std::cout << i << std::endl; }, 4, 5, 6);
}

Live Example

I thought that the second fold expression was meant to output the numbers in reverse order

6 5 4

How come the results are the same?

like image 485
Marco A. Avatar asked Jun 13 '15 14:06

Marco A.


1 Answers

According to § 14.5.3/9

The instantiation of a fold-expression produces:

(9.1) — ((E1 op E2) op · · · ) op EN for a unary left fold,

(9.2) — E1 op (· · · op (EN-1 op EN )) for a unary right fold,

(9.3) — (((E op E1) op E2) op · · · ) op EN for a binary left fold, and

(9.4) — E1 op (· · · op (EN-1 op (EN op E))) for a binary right fold

In each case, op is the fold-operator, N is the number of elements in the pack expansion parameters, and each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element.

in the code above they're both unary fold expressions and their expansion is

template<typename F, typename... T>
void for_each1(F fun, T&&... args) {

    // Unary right fold (fun(args_0) , (fun(args_1) , (fun(args_2) , ...)))
    (fun (std::forward<T>(args)), ...);
}

template<typename F, typename... T>
void for_each2(F fun, T&&... args) {

    // Unary left fold ((fun(args_0) , fun(args_1)) , fun(args_2)) , ...
    (..., fun (std::forward<T>(args))); 
}

so the expressions have the same evaluation order as defined by the comma operator and thus the output is the same.

Credits: thanks to my friend Marco who raised the original question in the first place and gave me the chance to solve this potentially-misleading issue.

like image 179
Marco A. Avatar answered Sep 19 '22 21:09

Marco A.