It can be annoying to have to define a whole separate function or functor just to pass a small piece of logic to an algorithm. In the previous section, we defined a new struct just so we could ask the sort algorithm to sort in reverse order. For small pieces of logic, it is often more convenient to use a lambda expression. A lambda expression is an anonymous (nameless) function that can be defined in place, right where it is needed.
The capture list specifies which variables from the surrounding scope should be accessible inside the lambda. Capturing allows the lambda to use these variables even though they are not passed as parameters. This can be useful for complex logic, but for simple cases where no outside variables are needed, the capture list can be left empty as []. (We will not make use of any captured variables in our examples.)
The parameters are like the parameters of a regular function. Like a regular function, they can be references (and should be if you want to modify the arguments or just avoid copies).
The spacing within the parameters for sort has been expanded for clarity. Lines 15-17 are the lambda function. It is the third parameter to sort. In practice, it would often be written like this:
sort(numbers.begin(), numbers.end(), [](int a, int b) { return a > b; });
This style of anonymous function is very useful for short, simple operations that are only needed in one place. In addition to being concise, they also help keep related code together, making it easier to see the logic being used to sort the collection. (As opposed to having to look elsewhere in the code to find the definition of a separate function or functor.)
In addition to being used as parameters to algorithms, lambda expressions are also useful for defining small functions on the fly for things like event handlers, callbacks, and other situations where a full function definition would be overkill. Languages like JavaScript make heavy use of lambda expressions for these purposes.