this piece of code is not something unknown to JS developers
function get_counter() { return ( function() { var c = 0; return function() { return ++c; }; })(); }
it basically creates a which creates different enumerators. So I was wondering if same thing can be done in C++11 with new lambda semantics? I ended up writing this piece of C++ which unfortunately does not compile!
int main() { int c; auto a = [](){ int c = 0; return [&](){ cout << c++; }; }; return 0; }
so I was wondering if there is a workaround to get it compiled and if there is how can compiler make this code run correctly? I mean it has to create separate enumerators but it should also collect garbage (unused c variables).
by the way I'm using VS2012 compiler and it generates this error:
Error 2 error C2440: 'return' : cannot convert from 'main::::()::' to 'void (__cdecl *)(void)' c:\users\ali\documents\visual studio 2012\projects\test\test\main.cpp 25 1 Test
Your code has a bug in that it contains a dangling reference; the c
reference will refer to the local variable in the outer lambda, which will be destroyed when the outer lambda returns.
You should write it using a mutable
by-value lambda capture:
auto a = []() { int c = 0; return [=]() mutable { cout << c++; }; };
This relies on a post-standard extension to allow multiple statements in a return-type-deducing lambda; Is there a reason on not allowing lambdas to deduce the return type if it contains more than one statement? The easiest way to fix it is to supply a parameter so that the lambda contains only a single statement:
auto a = [](int c) { return [=]() mutable { cout << c++; }; };
Unfortunately default parameters aren't allowed in lambdas, so you'd have to call this as a(0)
. Alternatively at the cost of readability you could use a nested lambda call:
auto a = []() { return ([](int c) { return [=]() mutable { cout << c++; }; })(0); };
The way this works is that when a
executes the inner lambda copies all the referenced variables into an instance of its closure type, which here would be something like:
struct inner_lambda { int c; void operator()() { cout << c++; } };
The instance of the closure type is then returned by the outer lambda, and can be invoked and will modify its copy of c
when called.
Overall, your (fixed) code is translated to:
struct outer_lambda { // no closure struct inner_lambda { int c; // by-value capture // non-const because "mutable" void operator()() { cout << c++; } } // const because non-"mutable" inner_lambda operator()(int c) const { return inner_lambda{c}; } };
If you left c
as a by-reference capture, this would be:
struct outer_lambda { // no closure struct inner_lambda { int &c; // by-reference capture void operator()() const { cout << c++; } // const, but can modify c } inner_lambda operator()(int c) const { return inner_lambda{c}; } };
Here inner_lambda::c
is a dangling reference to the local parameter variable c
.
It's a natural limitation of C++ that a lambda which captures by reference can't use the captured variable any more, once the variable no longer exists. So even if you get it to compile, you can't return this lambda from the function in which it appears (that also happens to be a lambda, but that's irrelevant), because the automatic variable c
is destroyed on return.
I think the code you need is:
return [=]() mutable { cout << c++; };
I haven't tested it and I don't know what compiler versions support it, but that's a capture-by-value, with mutable