C++

Lambda Expressions

12 question(s)

What is a lambda expression in C++?

Beginner
A lambda expression is an anonymous function object defined inline, introduced in C++11. It has the form [captures](params){ body } and can be stored, passed to algorithms, or called immediately. The compiler generates a unique closure type with an operator() containing the body.
auto add = [](int a, int b) { return a + b; };
int r = add(2, 3);  // 5
Real-world example A lambda is passed to std::sort to define a custom comparison inline instead of a named function.

Common follow-ups: What is the closure type? | Where are lambdas commonly used?

STL Templates Lambda Expressions

What is the capture list in a lambda?

Beginner
The capture list [...] specifies which surrounding variables the lambda can use and how. [x] captures x by value (a copy), [&x] by reference, [=] captures all used variables by value, [&] all by reference, and [this] captures the enclosing object. Captures let the lambda access local state.
int n = 10;
auto byVal = [n]()  { return n; };   // copy
auto byRef = [&n]() { n++; };        // reference
Real-world example A lambda captures a threshold value by value so it can filter a collection with std::count_if.

Common follow-ups: By value vs by reference capture? | What does [=] capture?

Lambda Expressions STL Lambda Expressions

What is the difference between capturing by value and by reference?

Intermediate
Capturing by value copies the variable into the closure at creation time, so later changes to the original don't affect the lambda and the copy is safe to use after the original's scope ends. Capturing by reference stores a reference, so the lambda sees later changes but causes dangling references if it outlives the captured variable.
int x = 1;
auto v = [x]  { return x; }; // frozen at 1
auto r = [&x] { return x; }; // reflects later x
x = 99;
Real-world example Capturing a local by reference in a lambda stored for later use causes a dangling-reference crash.

Common follow-ups: When is by-reference capture dangerous? | Does by-value reflect later changes?

References & Pointers Lambda Expressions Lambda Expressions

What is a mutable lambda?

Intermediate
By default, a lambda's operator() is const, so by-value captured variables can't be modified inside the body. Marking the lambda mutable removes the const, allowing modification of the by-value copies (the changes persist across calls to that lambda instance but don't affect the originals).
int n = 0;
auto counter = [n]() mutable { return ++n; };
counter(); counter();  // returns 1, then 2
Real-world example A mutable lambda maintains an internal counter across calls without an external variable.

Common follow-ups: Why is operator() const by default? | Do mutable changes affect the original?

Lambda Expressions Lambda Expressions Lambda Expressions

How do you specify a lambda's return type?

Intermediate
Usually the return type is deduced from the return statements. When deduction is ambiguous or you want an explicit type, use a trailing return type: [](int x) -> double { ... }. Explicit return types are also needed when different return statements would otherwise deduce different types.
auto f = [](int x) -> double {
    if (x > 0) return x;   // int
    return 0.5;            // double -> need explicit type
};
Real-world example An explicit -> double return type resolves a lambda that returns both int and double literals.

Common follow-ups: When must you specify the return type? | How is it deduced by default?

Type Deduction & auto Lambda Expressions Lambda Expressions

What is a generic (template) lambda?

Advanced
A generic lambda (C++14) uses auto for one or more parameters, making operator() a template so the lambda works with any argument types. C++20 adds explicit template parameter syntax. Generic lambdas enable writing reusable, type-agnostic inline functions, often used with algorithms over varied types.
auto print = [](const auto& x) { std::cout << x; };
print(42); print("hi");   // works for both

// C++20 explicit form
auto f = []<typename T>(T x) { return x + x; };
Real-world example A single generic lambda logs elements of containers holding different value types.

Common follow-ups: What does auto in a parameter create? | What did C++20 add?

Templates Type Deduction & auto Lambda Expressions

How are lambdas implemented under the hood?

Advanced
The compiler turns a lambda into an unnamed class (closure type) with a member operator() holding the body, and member variables for the captures (copies for by-value, references for by-reference). A captureless lambda is convertible to a plain function pointer. Because each lambda has a unique type, they're typically stored via auto or std::function.
// [x](int y){return x+y;} roughly becomes:
struct __lambda { int x; int operator()(int y) const { return x+y; } };
Real-world example Understanding that a lambda is a class with captured members explains why capture-by-reference can dangle.

Common follow-ups: Why is each lambda's type unique? | When is a lambda convertible to a function pointer?

Templates OOP & Classes Lambda Expressions

What is std::function and how does it relate to lambdas?

Intermediate
std::function is a type-erased, general-purpose polymorphic wrapper that can hold any callable (lambda, function pointer, functor) matching a given signature. It's useful for storing lambdas in containers or class members where the exact closure type can't be named, at the cost of some overhead versus auto or templates.
std::function<int(int)> f = [](int x){ return x*x; };
std::vector<std::function<void()>> callbacks;
Real-world example A UI framework stores button callbacks as std::function<void()> so any lambda can be registered.

Common follow-ups: Why not always use auto instead? | What overhead does std::function add?

Lambda Expressions Templates Lambda Expressions

Where are lambdas most commonly used?

Beginner
Lambdas are most commonly used as inline callables for STL algorithms (sort comparators, predicates for find_if/count_if/remove_if, transformations), as callbacks and event handlers, in threading (passing work to std::thread or std::async), and anywhere a short, local function is clearer than a named one.
std::sort(v.begin(), v.end(),
          [](int a, int b){ return a > b; }); // descending
Real-world example A predicate lambda passed to std::remove_if filters out invalid records in one line.

Common follow-ups: Which algorithms take predicates? | Why prefer a lambda over a named function here?

STL Concurrency Lambda Expressions

What is capturing by move (init capture) and when is it needed?

Advanced
C++14 init captures allow initializing a capture with an expression, including moving a move-only object into the closure: [p = std::move(ptr)]. This is needed to capture things like unique_ptr, which can't be copied, so the lambda takes ownership. It also lets you compute or rename captured values.
auto up = std::make_unique<int>(5);
auto f = [p = std::move(up)]() { return *p; }; // owns the unique_ptr
Real-world example A task lambda takes ownership of a unique_ptr resource via move capture so it can run on another thread.

Common follow-ups: Why can't you capture unique_ptr by value normally? | What else can init capture do?

Move Semantics RAII & Smart Pointers Lambda Expressions