C++11 lambda returning lambda

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 to say that the captured value can be modified by the lambda.

So each time you call a you get a different counter with its own count starting from 0. Each time you call that counter, it increments its own copy of c. As far as I understand Javascript (not far), that's what you want.


I think the problem is that the compiler cannot deduce the return type of the outer lambda (that assigned to a) because it consists of more than a simple one line return. But unfortunately there is also no way to explicitly state the type of the inner lambda. So you will have to return a std::function, which comes with some additional overhead:

int main()
{
    int c;
    auto a = []() -> std::function<void()> {
        int c = 0;
        return [=]() mutable {
            std::cout << c++;
        };
    };
    return 0;
}

And of course you have to capture by-value, like Steve already explained in his answer.

EDIT: As to why the exact error is that it cannot convert the returned inner lambda to void(*)() (pointer to void() function), I only have some guesses because I don't have much insight into their lambda implementation, which I'm not sure is that stable or standard-conformant at all.

But I think VC at least tries to deduce the return type of the inner lambda and realizes that it returns a callable. But then it somehow incorrectly assumes this inner lambda to not capture (or they are not able to determine the inner lambda's type), so they just make the outer lambda return a simple function pointer, which would indeed work if the inner lambda wouldn't capture anything.

EDIT: And like ecatmur states in his comment, returning a std::function is even neccessary when making an actual get_counter function (instead of a lambda), since normal functions don't have any automatic return type deduction.