Reputation: 75688
I always get confused by the lambda capture and I don't know if a variable is captured by reference or by value. For instance if I have [a]
I don't know if a
is captured by value or by ref.
I think a simple way to get it would be by examples. So let's have one for each of the cases (more if there are more ways of expressing the same thing):
Capture:
r1
, r2
by reference. Nothing else.v1
, v2
by value. Nothing else.r1
, r2
by reference. Rest by value.v1
, v2
by value. Rest by reference.r1
, r2
by reference, v1
, v2
by value. Nothing else.Let's completely ignore this
as that is another bag of worms.
Upvotes: 5
Views: 2062
Reputation: 3707
nothing
[]
all by reference
[&]
all by value
[=]
r1
, r2
by reference. Nothing else.
[&r1, &r2]
v1
, v2
by value. Nothing else.
[v1, v2]
r1
, r2
by reference. Rest by value.
[=, &r1, &r2]
v1
, v2
by value. Rest by reference.
[&, v1, v2]
r1
, r2
by reference, v1
, v2
by value. Nothing else.
[&r1, &r2, v1, v2]
Upvotes: 4
Reputation: 171117
| Capture | Syntax |
| --------------------------------------------- | ------------------ |
| nothing | [] |
| all by reference | [&] |
| all by value | [=] |
| r1, r2 by reference. Nothing else. | [&r1, &r2] |
| v1, v2 by value. Nothing else. | [v1, v2] |
| r1, r2 by reference. Rest by value. | [=, &r1, &r2] |
| v1, v2 by value. Rest by reference. | [&, v1, v2] |
| r1, r2 by ref, v1, v2 by value. Nothing else. | [v1, v2, &r1, &r2] |
The rule is simple: preceded by an &
, capture by reference. Name only, capture by value.
Defaults: =
all by value, &
all by reference. Things to exclude from "all" use the simple rule above.
The full rules can be read on cppreference.
Upvotes: 8
Reputation: 93264
In short:
[]{ } // do not capture anything
[foo]{ } // capture `foo` by value
[&foo]{ } // capture `foo` by reference
[foo, &bar]{ } // capture `foo` by value, `bar` by reference
[=, &foo]{ } // capture everything by value, `foo` by reference
[&, foo]{ } // capture everything by reference, `foo` by value
In C++14, you also have generalized lambda captures:
[i=0]{ } // create closure with `i` data member initialized to `0`
[i=j]{ } // create closure with `i` data member initialized to `j`
[i{0}]{ } // create closure with `i` data member initialized to `0`
[i{j}]{ } // create closure with `i` data member initialized to `j`
// create closure with `uptr` data member initialized to `std::move(uptr)`
[uptr = std::move(uptr)]{ }
// create closure with `foo` reference data member initialized to `something`
[&foo = something]{ }
If you want to conditionally capture either by reference or by value, you can use generalized lambda captures to implement some sort of "perfect-forwarding capture": "capturing perfectly-forwarded objects in lambdas".
Let's completely ignore
this
as that is another bag of worms.
[this]{ } // capture `this` by value (the pointer)
[*this]{ } // store a copy of `*this` inside the closure
[*this]
was introduced in C++17.
Note that [&this]
is a syntax error.
Upvotes: 14