Lambda

Motivation

  • E.g. <algorithm>: comparison function, etc.

  • Functions have to be defined elsewhere

  • … although used only once

  • ⟶ much typing

  • ⟶ loud

Reverse sorting …

static bool greater(int lhs, int rhs)
{
    return lhs > rhs;
}

// 2 kilometers down below ...
std::sort(v.begin(), v.end(), greater);

Lambda To The Rescue

  • “Lamda” (Python, Perl, …)

  • Definition is usage

Reverse sorting: lambda version …

std::sort(v.begin(), v.end(), [](int lhs, int rhs) { return lhs>rhs; });

Excursion: Python Closures

  • Python’s closures are all automatic

  • Created at function definition time

  • runtime

  • Closure = snapshot of names that are …

    • Undefined in local scope of defined function (print_message)

    • Defined in surrounding scope (parameter message of creating function create_print_function)

def create_print_function(message):
    def print_message():
        print(message)   # <--- message is 'in the closure of function object "print_message"'
    return print_message

p = create_print_function('howdy')
p()
$ python ../code/closure.py
howdy

Same In C++: Capturing

#include <functional>
#include <string>
#include <iostream>


static std::function<void()> create_print_function(const std::string& message)
{
    auto print_message = [message](){    // <--- message is 'captured into the closure of function object "print_message"'
        std::cout << message << std::endl;
    };
    return print_message;
}

int main()
{
    auto p = create_print_function("howdy");
    p();
    return 0;
}
$ code/c++11-lambda-capture
howdy
  • Here: explicit capture

  • Variable message is captured into lambda function object

  • Capture is by copy if not stated otherwise (see below)

So What Is That? (Answer: A Functor)

  • Functor: an instance of a class that happens to be callable (has operator()(...) defined)

  • Nothing more

Capturing By Reference ⟶ Careful!

#include <functional>
#include <string>
#include <iostream>


static std::function<void()> create_print_function(const std::string& message)
{
    auto print_message = [&message](){    // <--- message is 'captured into the closure of function object "print_message"'
        std::cout << message << std::endl;
    };
    return print_message;
}

int main()
{
    auto p = create_print_function("howdy");
    p();
    return 0;
}
$ code/c++11-lambda-capture-reference
howdy
  • Program creates a temporary std::string object ("howdy")

  • Lambda stores a reference to it, and uses it later

  • Attentive programmer jumps up and shouts!

Danger

Be very careful!

  • Use capture-by-reference only when references are use locally (for example, passing to algorithms)

  • Don’t use capture-by-reference in lambdas that you store on the heap, for example, or that you pass to other threads

More About Capturing

See Lambda: More Capturing