2011-09-15 CPlusPlus0X

More on Lambdas

As we saw in the example with computing the sum we could in the lambda bind a variable from the defining scope. This is also known as a closure. The functions is closed over its free variables. That is great, it has fancy name, can we look at more ways how to use it?

One new aspect is if we look at capture by value. In the sum example we bound sum by reference so we could update it inside the lambda. If we want the value at the creation time of the lambda we capture by value instead. It looks like this:

[var] (... // capture variable var by value
[=] (...   // capture all variables by value
int divBy = 2;
auto divBy2 = [divBy] (int x) { return x / divBy; };

divBy = 4;
auto divBy4 = [divBy] (int x) { return x / divBy; };

assert(4 == divBy2(8));
assert(2 == divBy4(8));

Yes, the first lambda divides by 2 and the second by 4. All because divBy is captured by value when we defined the lambda.

To go further, we can even bind this. So accessing and calling members from a lambda expression is possible. Let us define a class (using a struct to make the example less verbose)

struct Name 
{
   string name;
   void me() { cout << "I'm: " << name << endl; }
   function<void()> callMe() { return [&]() { me(); }; }
};

The first function member me is easy to understand. It prints the name of the object.

The second member callMe requires some explanation. First it introduces std::function. Let us settle for now that it declares a callable type taking no parameters and returning void. The lambda itself binds all members by reference and calls the member me.

Using it can look like this:

Name al {"Al"};
auto gl = al.callMe();
gl();    // Prints "I'm: Al"

This is like a function object but created with less typing.