SyntaxStudy
Sign Up
C++ Lambdas, std::function, and Closures
C++ Beginner 1 min read

Lambdas, std::function, and Closures

Lambda expressions are anonymous function objects defined inline at their point of use. A lambda consists of a capture clause '[]', an optional parameter list, an optional return type, and a body. Lambdas integrate naturally with STL algorithms, replacing the boilerplate of separate functor classes or function pointers. The compiler generates a unique closure type for each lambda, capturing variables from the enclosing scope as specified. The capture clause controls how the lambda accesses variables from its enclosing scope. Capture by value '[=]' copies variables at the point of lambda creation; capture by reference '[&]' stores a reference, which can dangle if the lambda outlives the captured variable. Individual variables can be specified explicitly: '[x, &y]' captures 'x' by value and 'y' by reference. 'std::function' is a type-erased wrapper that can store any callable with a matching signature — a free function, lambda, functor, or member function bound with 'std::bind'. It enables storing callbacks in containers and passing them across API boundaries without templates. The type-erasure has a small overhead; where performance is critical, templated callable parameters or 'auto' lambdas should be preferred.
Example
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <string>

int main() {
    // Basic lambda
    auto greet = [](const std::string& name) {
        std::cout << "Hello, " << name << "!\n";
    };
    greet("Lambda");

    // Capture by value
    int threshold = 5;
    auto isAbove = [threshold](int n) { return n > threshold; };
    std::cout << "6 above threshold: " << std::boolalpha << isAbove(6) << "\n";

    // Capture by reference — modifies outer variable
    int count = 0;
    auto increment = [&count]() { ++count; };
    increment(); increment(); increment();
    std::cout << "count = " << count << "\n";  // 3

    // Lambda in STL algorithm
    std::vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};
    std::sort(nums.begin(), nums.end(),
              [](int a, int b) { return a > b; });  // descending
    for (int n : nums) std::cout << n << " ";
    std::cout << "\n";

    // std::function — type-erased callable
    std::vector<std::function<int(int)>> transforms;
    transforms.push_back([](int n) { return n * 2;  });
    transforms.push_back([](int n) { return n + 10; });
    transforms.push_back([](int n) { return n * n;  });

    int val = 3;
    for (const auto& f : transforms)
        std::cout << "f(" << val << ") = " << f(val) << "\n";

    return 0;
}