40

How do I assign a lambda as default argument? I would like to do this:

int foo(int i, std::function<int(int)> f = [](int x) -> int { return x / 2; })
{
    return f(i);
}

but my compiler (g++ 4.6 on Mac OS X) complains:

error: local variable 'x' may not appear in this context

EDIT: Indeed, this was a compiler bug. The above code works fine with a recent version of gcc (4.7-20120225).

mavam
  • 12,242
  • 10
  • 53
  • 87
  • I wonder if it's an issue with gcc or if the standard forbids it. – Matthieu M. May 17 '11 at 06:33
  • 2
    Just to add, MSVC (2010) spews the same warning: `error C2587: 'x' : illegal use of local variable as default parameter` - `see declaration of 'x'`. It seems to because of the parameter, if I remove it from the lambda, `std::function` and function call, it compiles perfectly fine. – Xeo May 17 '11 at 17:45
  • @Xeo: I wonder how VC2011 reacts to this syntax, since it has improved lambda support. – Nicol Bolas Mar 05 '12 at 23:34
  • Works now (Feb 24, 2017) with clang-800.0.42.1 via `clang++ -c -std=c++11` – wcochran Feb 24 '17 at 20:33

2 Answers2

28

You could use overloading:

int foo(int i)
{
    return foo(i, [](int x) -> int { return x / 2; });
}

int foo(int i, std::function<int(int)> f)
{
    return f(i);
}
Tim Sylvester
  • 22,897
  • 2
  • 80
  • 94
  • Like Matthieu, I am not sure whether the issue is a bug in gcc or intentional. Your workaround seems the best solution at the moment. – mavam May 26 '11 at 05:45
  • 1
    Ahh, java-style default parameters. A sight for sore eyes (not!) –  Jan 11 '16 at 18:27
9

This seems to be a bug in gcc; the standard permits lambda expressions in default parameters as long as nothing is captured.

The following seems to be everything the FDIS says about lambdas in default parameters, so any use other than what is forbidden here ought to be permitted by default.

C++11 FDIS 5.1.2/13

A lambda-expression appearing in a default argument shall not implicitly or explicitly capture any entity.

[ Example:

void f2() {
    int i = 1;
    void g1(int = ([i]{ return i; })());       // ill-formed
    void g2(int = ([i]{ return 0; })());       // ill-formed
    void g3(int = ([=]{ return i; })());       // ill-formed
    void g4(int = ([=]{ return 0; })());       // OK
    void g5(int = ([]{ return sizeof i; })()); // OK
}

— end example ]

JohannesD
  • 13,802
  • 1
  • 38
  • 30
  • 2
    Note that, in all those examples there is no parameter, and that's what the compiler chokes on (even in VS2010). – Xeo May 17 '11 at 17:46
  • @Xeo - Yeah, but nowhere in the standard does it explicitly forbid parameters in lambdas used as default argument (that would be a very silly restriction indeed), so both compilers are simply buggy. – JohannesD May 17 '11 at 17:53
  • 2
    These examples are slightly different -- these are *executing* a lambda *to obtain* a function argument's default value; does this really imply that the lambda itself can be a default value? – ildjarn May 17 '11 at 19:15
  • @ildjarn - The example itself is non-normative, but the grammar clearly permits a default argument that is a lambda expression, and AFAICS there exists no normative text that specifically makes an exception to what the grammar says. – JohannesD May 17 '11 at 20:17