Lambdas are Anonymous Functions
A lambda expression (also called a lambda or closure) allows us to define an anonymous function inside another function. The nesting is important, as it allows us both to avoid namespace naming pollution, and to define the function as close to where it is used as possible.
The syntax for lambdas is one of the weirder things in C++:
[ captureClause ] ( parameters ) -> returnType
{
statements;
}
- The capture clause can be empty if no captures are needed.
- The parameter list can be empty is no parameters are required. It can also be omitted entirely unless a return type is specified.
- The return type is optional, and if omitted,
auto
will be assumed (thus using type deduction used to determine the return type).
Also note that lambdas (being anonymous) have no name, so we don't need to provide one.
A trivial lambda definition looks like:
#include <iostream>
int main()
{
[] {}; // a lambda with an omitted return type, no captures, and omitted parameters.
return 0;
}
Basic Syntax:
auto lambda = [](int a, int b) -> int {
return a + b;
};
- Here,
auto
is used to let the compiler deduce the lambda's return type and the lambda itself is defined between the square brackets ([]
). The parameter follow the lambda introducer, and the body is enclosed withing curly braces.
[capture_clause](parameter_list) -> return_type {
// lambda body
}
- Capture Clause: Specifies which variables are accessible inside the lambda.
- Parameter List: The list of input parameters, similar to a function.
- Return Type: The return type of the lambda, If omitted, the return type is deduced by the compiler.
- Lambda Body: The code block containing the logic of the lambda.
Capture Clauses:
Capture clauses determine how variables from the enclosing scope are accessed inside the lambda. Here are the main capture clauses:
1. Capture by Value:
int x = 5;
auto lambdaByValue = [x](int y) {
// x is captured by value
};
2. Capture by Reference:
int x = 5;
auto lambdaByValue = [&x](int y) {
// x is captured by reference
};
3. Capture All Variables:
int x = 5, y = 10;
auto lambdaCaptureAll = [=]() {
// x and y are captured by value
};
4. Capture All Variables by Reference:
int x = 5, y = 10;
auto lambdaCaptureAllByReference = [&]() {
// x and y are captured by reference
};
Generic Lambdas:
Starting from C++14, lambdas can be made generic by using the auto
specifier in the parameter list. This allows them to operate on a variety of types.
int x = 5, y = 10;
auto lambdaCaptureAllByReference = [&]() {
// x and y are captured by reference
};
Lambda Return Type Deduction:
If the return type of a lambda is not specified, the compiler can deduce it based on the return statements within the lambda body.
auto lambdaWithAutoReturnType = [](int a, int b) {
return a + b; // Compiler deduces the return type as int
};