⚙️ C++

Lambda-Funktionen und funktionaler Stil in C++: eine ausführliche Anleitung

What is it and why? (Real-life analogy)

Imagine you go to a fast food restaurant. You walk up to the counter and say, "Make me a burger." The cook takes a patty, a bun, some vegetables, and wraps it all in paper. Now imagine you don't say "make me a burger," but instead give the cook instructions right on the spot: "Take the patty, fry it for 3 minutes, put it on the bun, add a lettuce leaf, and wrap it up." This is a lambda function — you are not using a pre-prepared recipe (a regular function), but creating it "on the fly," right where it is needed.

In programming, situations often arise where you need to perform some simple action, but writing a separate function for it is like calling a head chef for a single sandwich. Lambda functions allow you to define behavior directly in the code, without the distraction of creating named functions.

Important: Lambda functions are not magic, but simply convenient syntactic sugar. Internally, the compiler still creates a regular function but hides this process from you.

Theory: How it works internally

To understand lambda functions, you need to look "under the hood" of the compiler. When you write a lambda, the compiler creates an anonymous class (a class without a name) with the operator(). This class is called a functor or a function object.

Consider the simplest lambda:

auto lambda = [](int x) { return x * 2; };

The compiler transforms it into something like this:

class __AnonymousLambdaClass {
public:
    int operator()(int x) const {
        return x * 2;
    }
};

auto lambda = __AnonymousLambdaClass();

Now it becomes clear why lambdas can "capture" variables from the outer scope. If you write [=] or [&], the compiler adds corresponding fields to this anonymous class.

int multiplier = 3;
auto lambda = [multiplier](int x) { return x * multiplier; };

// The compiler creates:
class __AnonymousLambdaClass {
    int multiplier;  // captured variable
public:
    __AnonymousLambdaClass(int m) : multiplier(m) {}
    int operator()(int x) const {
        return x * multiplier;
    }
};
Important: By default, a lambda function is const — it cannot modify captured variables. To allow modification, you need to add the mutable keyword.

Syntax in C++: All forms and variants

The full syntax of a lambda function looks like this:

[capture](parameters) specifiers return_type { body }

Let's break down each part:

Part Description Example
[capture] Defines which variables from the outer scope are accessible inside the lambda [x, &y]
(parameters) Input parameters, like a regular function (int a, int b)
specifiers Additional modifiers: mutable, constexpr, noexcept mutable
return_type Explicit specification of the return type (optional) -> int
{ body } The code that executes when the lambda is called { return a + b; }

Variable capture options

Syntax What it does
[] Captures nothing
[x] Captures x by value (copy)
[&x] Captures x by reference
[=] Captures all used variables by value
[&] Captures all used variables by reference
[=, &x] All by value, except x (by reference)
[&, x] All by reference, except x (by value)
[this] Captures the current class object (for methods)

Specifiers

  • mutable — allows modifying captured-by-value variables inside the lambda
  • constexpr — indicates that the lambda can be evaluated at compile time
  • noexcept — guarantees that the lambda does not throw exceptions

Code examples — from simple to complex

Example 1: Simplest lambda

#include <iostream>

int main() {
    // Create a lambda that takes two numbers and returns their sum
    auto sum = [](int a, int b) {
        return a + b;
    };
    
    // Call the lambda like a regular function
    int result = sum(5, 3);
    std::cout << "Sum: " << result << std::endl;  // Output: Sum: 8
    
    return 0;
}

Explanation: auto sum — the compiler determines the lambda type itself. [](int a, int b) — empty capture and two parameters. { return a + b; } — the body