Lambdas and captures
Inline, anonymous functions that can grab variables from the enclosing scope by value or by reference.
[capture](params){ body } builds a callable on the spot β the capture list decides which surrounding variables it sees, mutable lets it keep state, and auto parameters make it generic.
A lambda is an unnamed function you write right where you use it. The full shape is [captures](parameters) -> return { body }, but the return type is usually deduced, so most lambdas read as [captures](params){ body }. You can call it immediately, store it in a variable with auto, or hand it to an algorithm.
The piece unique to lambdas is the capture list in []. An ordinary function only sees its parameters and globals; a lambda can also reach the local variables that exist where it is defined. The capture list names which of those locals it pulls in, and whether it takes a copy or a reference.
Capture by value vs by reference
[x] captures x by value β the lambda stores its own copy, frozen at the moment of capture; later changes to the outer x are invisible to it. [&x] captures by reference β the lambda refers to the original variable, so it sees later changes and can write back through it. The shorthands [=] and [&] capture every used local by value or by reference respectively, but naming captures explicitly is clearer and safer.
Reference captures come with a lifetime rule: the captured variable must outlive every call to the lambda. Returning a lambda that holds [&local] is a dangling-reference bug. For anything that escapes the current scope, capture by value (or capture a copy via [y = x]).
mutable and generic lambdas
By default a lambda's operator() is const, so value-captured members are read-only inside the body. Marking the lambda mutable drops that const, letting it modify its own captured copies between calls β the basis of a tiny stateful counter that remembers a value across invocations without a separate class.
Since C++14, a parameter typed auto makes the lambda generic: the compiler stamps out a call operator for each argument type you use it with, so one lambda works on int, double, std::string, and more. This pairs naturally with the standard algorithms, where lambdas most often appear as comparators and predicates.
Try it 5 examples
Define and call a lambda
C++introsquare behaves like any callable β square(5) is 25 and nesting square(square(2)) squares 4 to 16, while the capture-free greet shows a lambda needs neither parameters nor a capture list.