Lambda capture

If there is a lambda capture [=, &var] does it mean that it can access all the variables in the scope in which it is defined by value except for var? Also does [&var, =] mean the same thing?
If there is a lambda capture [=, &var] does it mean that it can access all the variables in the scope in which it is defined by value except for var?

Yes, except that if there is a current object, it (i.e. *this) is also captured by reference.

This is because if the current object is implicitly bound it always captured by reference. To capture the current object by value it must be explicitly captured by value: ([=, *this])

Also does [&var, =] mean the same thing?
No, because that's a syntax error. The capture-default must appear first in the capture list.
mbozzi wrote:
Yes, except that if there is a current object, it (i.e. *this) is also captured by reference.

This is because if the current object is implicitly bound it always captured by reference.

@mbozzi, could you please explain me better this point?
Aren’t all pointers captured as they are, i.e. pointers?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <limits>

void waitForEnter();

int main()
{
    int* pint = new int(5);
    std::cout << "pint: " << *pint << '\n';
    [=]{ (*pint)++; } ();
    std::cout << "pint: " << *pint << '\n';
    waitForEnter();
    return 0;
}

void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

output:
pint: 5
pint: 6

Press ENTER to continue...

What am I missing?
Aren’t all pointers captured as they are, i.e. pointers?

C++ has idiosyncratic rules about this in a lambda capture list. If the form this appears in a capture list, or it is captured implicitly, the members bound by the current object *this are visible in the closure, roughly like the lambda expression was a member function. Plain old this can only be captured by value (because the capture &this is a syntax error), and it allows transparent access to the members of the current object:

1
2
3
4
struct A { 
  int x = 0;
  int f() { [this]() { return x++; }(); } // A::x is visible.  
} a;

Each time you call a.f(), a.x is incremented again.

C++17 supplies a mechanism to copy the current object into the lambda by explicitly adding *this to the capture list:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# include <iostream>

struct A {
  // Note: *this is captured by reference.
  auto make_get_n_ref() { return [this](){ return n; }; }
  // Note: *this is captured by value
  auto make_get_n_val() { return [*this](){ return n; }; }
  int n = 1; 
};

int main() {
  A a;
  // the value that foo() will return is fixed at the 
  // point the closure was created
  auto foo = a.make_get_n_val();  
  
  // the value that bar() will return depends on the value of a.n 
  // at the time of the call
  auto bar = a.make_get_n_ref();
 
  std::cout << foo() << ", " << bar() << '\n';
  a.n = 2;
  std::cout << foo() << ", " << bar() << '\n';
}

http://coliru.stacked-crooked.com/a/cbfd422b569b5330
Last edited on
Uh, I see what you mean. Thanks a lot for your kind explanation, mbozzi, I didn’t know it was possible to capture the current object by copy (it sounds potentially expensive, anyway).
Topic archived. No new replies allowed.