12

Consider the following code:

template <typename F, typename X0, typename X1, typename... Xs>
auto fold_left(F&& f, X0&& x0, X1&& x1, Xs&&... xs)
{
    auto acc = f(x0, x1);
    return ([&](auto y){ return acc = f(acc, y); }(xs), ...);
}

const std::string a{"a"}, b{"b"}, c{"c"}, d{"d"}, e{"e"};
const auto cat = [](auto x, auto y) { return "(" + x + ", " + y + ")"; };

When invoking and printing fold_left(cat, a, b, c), both g++7 and clang++5 output:

((a, b), c)


When invoking and printing fold_left(cat, a, b, c, d) (more than 3 arguments), clang++5 outputs:

(((a, b), c), d)

Instead g++7 produces a weird compile-time error (shortened):

prog.cc: In instantiation of 'auto fold_left(F&&, X0&&, X1&&, Xs&& ...) [*...*]':
prog.cc:17:43:   required from here
prog.cc:8:13: error: member 'fold_left(F&&, X0&&, X1&&, Xs&& ...) [*...*]
    ::<lambda(auto:1)>::<acc capture>' is uninitialized reference
     return ([&](auto y){ return acc = f(acc, y); }(xs), ...);
             ^
prog.cc:8:13: error: member 'fold_left(F&&, X0&&, X1&&, Xs&& ...) [*...*]
    ::<lambda(auto:1)>::<f capture>' is uninitialized reference

live example on wandbox


Is my code ill-formed for some reason, or is this a g++7 bug?

W.F.
  • 13,888
  • 2
  • 34
  • 81
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416

1 Answers1

10

This is gcc bug 47226. gcc simply does not allow producing a pack expansions of lambdas like that.

However, there's no reason for you to put the lambda in the pack expansion. Or even to use a lambda at all:

template <typename F, typename Z, typename... Xs>
auto fold_left(F&& f, Z acc, Xs&&... xs)
{
    ((acc = f(acc, xs)), ...);
    return acc;
}
Barry
  • 286,269
  • 29
  • 621
  • 977