C++ lambdas allow you to capture variables from their surrounding scope, enabling powerful and flexible behavior. There are several ways variables can be captured, each with its own syntax and purpose.
1. Capture by Value: [=]
or [x]
- Syntax:
[=]
captures all automatic variables used in the lambda by value (i.e., makes a copy). - Syntax:
[x]
captures onlyx
by value. - Use when: You want the lambda to access, but NOT modify, external variables.
int x = 10;
auto f = [x]() { std::cout << x << "\n"; }; // captures x by value (a copy)
x = 20;
f(); // prints 10
2. Capture by Reference: [&]
or [&x]
- Syntax:
[&]
captures all automatic variables used in the lambda by reference. - Syntax:
[&x]
captures onlyx
by reference. - Use when: You want the lambda to be able to modify external variables.
int x = 10;
auto f = [&x]() { x = 15; };
f();
std::cout << x << "\n"; // prints 15
3. Mixed Capture
You can mix capture types for different variables:
int x = 1, y = 2;
auto f = [x, &y]() { std::cout << x << " " << y << "\n"; };
- Here,
x
is captured by value,y
by reference.
4. Default Plus Specific
You can set a default and override for specific variables:
int x = 3, y = 4;
auto f = [=, &y]() { std::cout << x + y << "\n"; }; // x by value, y by reference
5. Capture Everything by Value or Reference
[=]
: all used automatic variables by value.[&]
: all used automatic variables by reference.
6. C++14 Generalized Capture (Init Capture)
You can initialize new variables in the capture list (C++14 and above):
int val = 5;
auto f = [z = val + 2]() { std::cout << z << "\n"; }; // captures a new variable z = 7
Example Code: Exploring Capture Modes
Try the following code to experiment with captures:
#include <iostream>
int main() {
int a = 1, b = 2;
// Capture by value
auto byValue = [a]() { std::cout << "by value: " << a << "\n"; };
a = 10;
byValue(); // prints 1
// Capture by reference
auto byRef = [&b]() { b = 20; };
byRef();
std::cout << "by reference: " << b << "\n"; // prints 20
// Mixed capture
int c = 3, d = 4;
auto mixed = [c, &d]() { std::cout << "mixed: " << c << ", " << d << "\n"; };
d = 40;
mixed(); // prints 3, 40
// Init capture (C++14+)
int e = 5;
auto initCap = [x = e + 5]() { std::cout << "init capture: " << x << "\n"; };
initCap(); // prints 10
}
Summary Table of Capture Types
Capture Syntax | Captures | Can Modify? |
---|---|---|
[=] | All by value | No |
[&] | All by reference | Yes |
[x] | Only x, by value | No |
[&x] | Only x, by reference | Yes |
[=, &x] | All by value, x by reference | x only |
[&, x] | All by reference, x by value | All but x |
[x = y + 1] | Initializes x inside the lambda (C++14+) | x only |
Experiment with these different capture modes to get a deeper understanding of how lambdas interact with their surrounding variables in C++.
If you are new to Lambda check my Lambda post to know about them.