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

911 views Asked by At

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?

1

There are 1 answers

0
Marco A. On BEST ANSWER

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.