C++0x has a workload of new features[2]...

Today I'm having a look at lambdas. Lambdas are available in g++-4.5, for now only available in experimental.

What are lambdas?

operator()

You can think of it as something akin to a struct with. But it's a more than that: it's closer from a closure , something that Scheme fans are very familiar with: the closure code block captures its outter environment in its body.

Closures are a very powerful tool that are being retrofitted in many languages (for instance Java). They can be used as building blocks for many useful programing idioms such as continuations.

Enough for theory, let's have a look at this new beast.

How do they look like?

[](int i) { return i + 1; };

This is the increment lambda. You can declare a lambda in any function or method. Written like this, the lambda compiles[1] but it's not very useful: it's an anonynous lambda that is neither stored nor used.

How to read this? The square brackets open the declaration of a lambda. Then you declare lambda parameters and its body. Nothing suprising so far except for the declaration opening.

Using a lambda

[](int i) { return i + 1; }(0);

1

To use it add arguments, for instance:would compute the value

Storing a lambda

auto

auto inc = [](int i) { return i + 1; }; std::cout << inc(0) << std::endl;

->

auto mult = [](int x, double y) -> double { return x * y; };

The type of a lambda is automatically deduced. You can hint its return type if you need to. To store it you need to use another new C++0x keywork,, that was taken back from C:Notice that calling a named lambda is not different from calling a function. If you need to hint the lambda return type you can use

Capturing environment

void f() { int x = 5; [](int w) { return w + x; }(0); }

x

void f() { int x = 5; [=](int w) { return w + x; }(0); }

=

x

x

void f() { int x = 5; [=](int w) { return w + ++x; }(0); }

x

void f() { int x = 5; [=](int w) mutable { return w + ++x; }(0); }

mutable

x

void f() { int x = 5; [&](int w) { return w + ++x; }(0); }

x

struct A { int z; A() : z(0) {} void f() { int x = 5; [this, &x](int w) { z = w + ++x; }(0); std::cout << "x: " << x << ", z: " << z << std::endl; } };

f()

this

this->z

x

Complete example

#include <algorithm> #include <iostream> #include <vector> int main(int argc, char* argv[]) { std::vector<int> v = { 1, 2, 3 }; // Show then increment std::for_each(v.begin(), v.end(), [](int& e) { std::cout << e++ << std::endl; }); // Show content now std::for_each(v.begin(), v.end(), [](int e) { std::cout << e << std::endl; }); return 0; }

You can use lambdas to capture outter environment. A more complex, not working, example:Tha lambda declaration + invocation does not work, because thevariable we're referring to is declared in the outter scope. To enable capture of the outter scope, we can rewrite the previous example like this:Thesign in the square brackets (which are really the capturing clause) means we will copy every variable from the outter scope. Hence we can accessfrom our anonymous lambda. Now what if you want to changeThis does not compile: the environment is read-only by default. If you really want to incrementthen you need to write:Yes,. The value returned from the lambda is what you would expect. But guess what?value ischanged when the lambda returns. Indeed, we've copied outter scope variables by value. To really affect outter scope you need to change the capture clause:We use the ampersand to capture the environment by reference, and thus we can changevalue. We could also be more explicit about what we want to capture:The lambda inexplicitely mentions environment variables which are captured by value:, because we change, and also the local variableIt's easier to write functionnal-style code. As Sarah just said: 10 years from now everyone will realize how powerful functional programming is, then we'll be the masters of the universe!