A lambda expression can refer to identifiers declared outside the lambda expression. If the identifier is a local variable or a reference with automatic storage duration, it is an up-level reference and must be "captured" by the lambda expression. Such a lambda expression must be introduced by [lambda-captureopt], where lambda-captureopt specifies whether identifiers are captured by reference or by copy. The table below summarizes forms of lambda-captureopt.
Symbol |
Indicates |
---|---|
[] |
Nothing to capture: an up-level reference is an error |
[&x, y, ...] |
Capture as specified: identifiers prefixed by & are captured by reference; other identifiers are captured by copy. An up-level reference to any variable not explicitly listed is an error |
[&] |
Capture by reference: an up-level reference implicitly captures the variable by reference |
[=] |
Capture by copy: an up-level reference implicitly captures the variable by copy |
[&, x, y, ...] |
Capture by reference with exceptions: listed variables are captured by value/copy (no listed variable may be prefixed by &) |
[=, &x, &y, ...] |
Capture by copy with exceptions: listed variables are captured by reference only (every listed variable must be prefixed by &) |
No identifier may appear twice in the list. In the following code that sets area to the sum of the areas of four circles, the notation [&area,pi] specifies that area is captured by reference and pi by copy.
float radius[] = {2,3,5,7};
float area=0;
float pi = 3.14f;
for_each(radius, radius+4, [&area,pi](float r) {
return area+=pi*r*r;)
}
When a default capture is specified, the list must specify only the other kind of capture. In other words, if you specify that the default capture is by reference, then you must list (and only list) the variables that should be captured by copy. For example, if your intent is to capture x by reference and y by copy, and both x and y appear in the function body, the following code illustrates what is correct and incorrect code:
[&,&x,y] // ERROR - default is capture-by-reference; you must list only capture by copy
[&,y] // CORRECT
[=,&x,y] // ERROR - default is capture-by-copy; you must list only capture by reference
[=,&x] // CORRECT - default capture is by copy and so you must list x to be captured by reference
[&x] // ERROR - since there is no default capture, you must list y
[y] // ERROR - again no default capture is specified, so you must list &x
[&x,y] // CORRECT - since no default is specified, every variable is listed with its capture mode.
The following lambda expressions demonstrate default binding modes. All three expressions are semantically equivalent. Each captures x and y by reference, and captures a and b by copy.
[&x,&y,a,b](float r) {x=a; y=b;}
[&,a,b](float r) {x=a; y=b;}
[=,&x,&y](float r) {x=a; y=b;}
If a lambda expression occurs inside a member function, it can refer to this. Because this is not a variable, it cannot be captured by reference. Even when it is captured implicitly in a lambda expression introduced by [&], it is captured by copy.