CppLambda Expressions

Lambda Expressions

A lambda expression (C++11) is a way to write an anonymous, inline function — a small function object defined exactly where it's used, without needing a separate named function or a hand-written functor class. Lambdas are especially useful as short callbacks passed to STL algorithms.
Basic Syntax

CPP
#include <iostream>
using namespace std;

int main() {
    // [capture](parameters) -> returnType { body }
    auto add = [](int a, int b) -> int {
        return a + b;
    };

    cout << add(3, 4) << endl; // Output: 7

    return 0;
}
The -> returnType part is optional — the compiler can usually deduce the return type automatically from the return statement(s) in the body, so it's often omitted for simple lambdas.

CPP
auto multiply = [](int a, int b) {
    return a * b; // return type deduced as int
};

cout << multiply(3, 4) << endl; // Output: 12
Capture Modes
The [...] at the start of a lambda is its capture list — it controls which variables from the surrounding scope the lambda body can access, and whether it accesses them by value or by reference.

Capture

Meaning

[]

Captures nothing; the lambda can only use its own parameters

[=]

Captures all used outer variables by value (copies)

[&]

Captures all used outer variables by reference

[x]

Captures only x, by value

[&x]

Captures only x, by reference

CPP
int threshold = 10;
int count = 0;

// [threshold] - captured by value, a snapshot at creation time
auto isAboveThreshold = [threshold](int x) {
    return x > threshold;
};

// [&count] - captured by reference, so this really modifies 'count'
auto tally = [&count](int x) {
    count += x;
};

tally(5);
tally(3);
cout << count << endl; // Output: 8
Note
A variable captured by value is copied at the moment the lambda is created, not each time it is called — later changes to the original variable are not seen by the lambda. A variable captured by reference always reflects the current value of the original.
Lambdas with STL Algorithms

One of the most common uses for lambdas is providing a custom comparator or predicate to an STL algorithm on the spot, instead of writing a separate named function just for that one call.

CPP
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> nums = {5, 2, 8, 1, 9, 3};

    // Sort in descending order using a lambda as the comparator
    sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;
    });

    for (int n : nums) {
        cout << n << " ";
    }
    cout << endl;
    // Output: 9 8 5 3 2 1

    return 0;
}

CPP
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8};

    // Count how many elements are even, using a lambda predicate
    int evenCount = count_if(nums.begin(), nums.end(), [](int n) {
        return n % 2 == 0;
    });

    cout << "Even numbers: " << evenCount << endl; // Output: Even numbers: 4

    return 0;
}
Storing Lambdas: auto and std::function
Since every lambda has its own unique, compiler-generated type, auto is the simplest way to store one in a variable. If you need a variable that can hold different callables (a lambda, a function pointer, a functor) at different times, or you need to store it as a class member or pass it across a function boundary with a fixed type, wrap it in std::function.

CPP
#include <functional>
#include <iostream>
using namespace std;

int main() {
    auto square = [](int x) { return x * x; }; // simplest: auto

    std::function<int(int)> op = square; // std::function: a fixed, storable type
    op = [](int x) { return x + 1; };    // can be reassigned to a different lambda

    cout << square(5) << endl; // Output: 25
    cout << op(5) << endl;     // Output: 6

    return 0;
}
Tip
Prefer auto for local variables holding a single lambda — it's zero-overhead. Reach for std::function when you need type erasure, such as a class member, a container of callbacks, or a function parameter that should accept any callable.
Key Points
  • Lambda syntax: capture -> returnType { body }; the return type is usually deducible and omitted.

  • [] captures nothing, [=] captures by value, [&] captures by reference; specific variables can be listed individually.

  • Lambdas are widely used as inline comparators/predicates for STL algorithms like sort and count_if.

  • auto is the simplest way to store a lambda; std::function is used when a uniform, storable callable type is needed.

  • Values captured by [=] are snapshotted at creation time, not re-read on each call.