A Basic Example

void main()
    // Define the lambda:
    auto functionName = [] () { cout << "Hello World."; };

    // Call the lambda:

    // Here's a lambda with arguments:
    auto arg_lambda = [] (int x, int y) { cout << x << ", " << y; };

    // Calling it:
    arg_lambda(1, 2);
  • auto functionName = Assign the lambda to a variable we can reference.
  • [] The lambda operator.
  • () Same as every function argument list. Optional if empty.
  • { ... } The body of the lambda.

C++ is back to its old bad habits of overloading its operators with drastically different meanings that both you and the compiler must infer from the context.

The operator [] we all know from our old friend, the array definition. This time it has been re-purposed to define the lambda.

They’ve done this to us before. Anybody who remembers their first time with pointers in C, and trying to decipher if *my_variable was going to define a pointer, or deference to some other type will now be suffering flashbacks.

The thing to look for here is that the [] operator for lambdas will not follow a variable name.

my_array[] = { 1, 2, 3 }; // defines an array
my_lambda = [] { return my_array; }; // defines a lambda

You can think of [] as the name of a function, since it follows pretty much the same format:

auto myFunction() -> void { ... };
[] () -> void { ... };

Lambdas work like an expression

template<typename MyFunctionType>
void printStuff(MyFunctionType my_function)
    // The lambda is passed in as an argument and actually called here.

void main()
    // Define the lambda here
    auto functionName = [] { cout << "Hello World."; };

    // Pass it to the method here

    // Or just define it on the spot like a slob:
    printStuff( [] { cout << "Hello on the fly."; } );

Variable Capture

Lambdas can cheat on scope and use variables defined outside.

void main()
    string name;
    cin >> name;

    auto func = [&] { cout << "Hello " << name; };
  • [&] Defines a lambda with variable capture ability. Specifically capture by reference. (The value can be modified outside the lambda!)
  • [=] Will copy the variable to the lambda’s scope for use.
  • [=, &x] With this notation, you can copy all captured variables for local use, but define the variable named x to be captured by reference. Replace x with your specific variable name.
  • [x] Captures x only as a copy.
  • [this] Captures the this pointer of the class that calls it.

Return Values

Lambdas can be given return values like functions:

// compiler guess you are returning an int.
[] () { return 1; };

Return types might need to be made more clear:

// programmer is explicitly defining the return type:
[] () -> int {return 1;};
  • -> int Defines the return type as int.

This is a new C++ 11 way of defining return types.

// this
int myFunction();

// becomes this
auto myFunction() -> int;

So they are doing it to us again with the overloaded arrow operator. I think that keeping a certain level of confusion in the language is meant as an attempt to sort the new programmers from the greybeards.

MyDynamicObject -> myMethod();

// is completely different than this use of ->

[] () -> std::string { ... };

Lambdas as Arguments and Return Types

Use std::function as the type when you want to collect a lambda in the argument list or return one from your “lambda factory” method.

This requires the #include <functional> header to use.

So you could skip the template and do this:

template<typename MyFunctionType>
void printStuff(MyFunctionType my_function)
    // The lambda is passed in as an argument and actually called here.

// becomes this:

void printStuff(std::function<void()> my_function)

Or if an argument is required for the lambda:

void myFunction(std::function<void (string)> my_lambda)
    string my_string = "Hello World.";

// call it
myFunction([] (string x) { cout << "my string x=" << x; });

// prints:
// my string x=Hello World.

Or the lambda will have a return value:

void myFunction(std::function<bool (string)> my_lambda)
    string my_string = "Hello";
    bool is_printable = my_lambda(my_string);

// call it
myFunction( [] (string x) -> bool {
    if (isPrintable(x)) return true;
    else return false;

Or the lambda will have multiple arguments:

void myFunction(std::function<string (string, int)> my_lambda)
    string my_string = "Hello";
    int my_int = 1;
    cout << my_lambda(my_string, my_int);

Or as a return value:

std::function createFunctions()
    return [] () -> int { return 42; };

And you can see if std::function has been assigned a function by treating it like a bool:

std::function<int ()> myFunciton;

if (myFunction) {
    // will not execute

myFunction = [](){cout << "Hello World.";};

if (myFunction) {
    // will print "Hello World."


Why use lambdas?

  • Easier to implement than creating a delegate to pass one or two functions as parameters.
  • Look at JavaScript and JQuery and see all the uses for closures. It’s the same thing. Lambdas make for great callback arguments.
  • Use with iterators in a for_each method:

    vector my_vector;

    for_each(my_vector.begin(), my_vector.end(), [] (string list_item) { cout « list_item « endl; });

  • Pass an action to a function without wrapping it up in a class.

My Opinion

I hate nesting. Lambdas that get defined as in-line functions are going to add another nested layer to your code.

In my code, I like to keep things clean. I don’t want to go searching for that opening brace. Especially in loops. I tend to nest a try/catch block immediately within loops so any exceptions don’t break them. That already adds too many nested blocks.

You will more often than not see my code called like this:

myFunction (std::vector<std::string> string_list) {
    for_each(string_list.begin(), string_list.end(), [] (std::string list_item) {

The eachListItem() will contain the try/catch block and any logic. This reduces the nesting and improves readability. This is a pattern I follow in JavaScript all the time, where my closures just call some other function to do the work.

Inline functions are neat, and they have their uses. But I believe that a function should do one thing, and one thing only. When we start defining functions in-line like this it can get out of hand real fast.