bolov
bolov

Reputation: 75688

Lambda Captures

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:

Let's completely ignore this as that is another bag of worms.

Upvotes: 5

Views: 2062

Answers (3)

Garf365
Garf365

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

| 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

Vittorio Romeo
Vittorio Romeo

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

Upvotes: 14

Related Questions