C++ by Example
C++ by Example

Lambdas and std::function

2 min read

Lambdas and std::function

Lambdas are anonymous functions defined inline. They are especially useful when you need to pass behavior as an argument — to a sorting function, an algorithm, or a callback.

Basic lambda syntax

#include <iostream>

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

    std::cout << square(5) << "\n";   // 25
    std::cout << square(9) << "\n";   // 81
}

The parts: [] is the capture clause (covered next), (int x) is the parameter list, and { return x * x; } is the body. The return type is deduced automatically.

Lambdas with algorithms

The most common use of lambdas is with standard library algorithms:

#include <iostream>
#include <vector>
#include <algorithm>

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

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

    for (int n : v) std::cout << n << " ";   // 9 8 5 3 2 1
    std::cout << "\n";
}

Capture clause

A lambda can capture variables from the enclosing scope:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    int threshold = 5;

    std::vector<int> v = {1, 3, 7, 2, 9, 4, 6};

    // Capture threshold by value
    auto above = std::count_if(v.begin(), v.end(),
        [threshold](int x) { return x > threshold; });

    std::cout << above << " values above " << threshold << "\n";   // 3
}

Capture modes:

Syntax Meaning
[x] Capture x by value (copy)
[&x] Capture x by reference
[=] Capture all used variables by value
[&] Capture all used variables by reference
[=, &x] Capture all by value, but x by reference

Capture by reference is efficient but dangerous if the lambda outlives the captured variable.

Mutable lambdas

By default, a by-value capture is const inside the lambda. Use mutable to modify it:

int count = 0;
auto increment = [count]() mutable {
    count++;
    return count;
};

std::cout << increment() << "\n";   // 1
std::cout << increment() << "\n";   // 2
std::cout << count << "\n";         // 0 — the original is unchanged

std::function

std::function<R(Args...)> is a type-erased wrapper that can hold any callable — a lambda, a free function, a member function, or a functor — with a compatible signature:

#include <functional>
#include <iostream>

void apply(int x, std::function<int(int)> fn) {
    std::cout << fn(x) << "\n";
}

int double_it(int x) { return x * 2; }

int main() {
    apply(5, double_it);                     // 10
    apply(5, [](int x) { return x * x; });  // 25

    std::function<int(int)> fn = [](int x) { return x + 1; };
    apply(5, fn);                            // 6
}

std::function has overhead from type erasure. When performance matters and you only need one concrete type, use a template parameter instead:

template <typename F>
void apply(int x, F fn) {
    std::cout << fn(x) << "\n";
}
C++ by Example
C++ by Example

Learn modern C++ through working code. Each chapter introduces one concept — variables, functions, classes, templates, smart pointers, concurrency — with a clear example, a line-by-line explanation, and notes on how it applies in real programs.

View book →