Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 lambda capture `this` and capture local variables by value

Tags:

c++

c++11

lambda

The lambda function below captures this (so bar() can access its instance vars) and the local variables a,b,c.

class Foo {
  int x, y, z;
  std::function<void(void)> _func;
  // ...
  void bar() {
     int a,b,c;
     // ...
     _func = [this,a,b,c]() { // lambda func
        int u = this->x + a;
        // ...
     };
  }
};

But if I want to capture many instance variables and wish to avoid explicitly naming them in the capture list, I do not seem to be able to do this:

     _func = [this,=]() { // lambda func
        // ...
     };

I get a compiler error at the = following this,:

  error: expected variable name or 'this' in lambda capture list 

If I try this

     _func = [=,this]() { // lambda func
        // ...
     };

I get

  error: 'this' cannot be explicitly captured when the capture default is '='

Is there a shorthand for capturing this and everything else by value?

UPDATE: [=, this] as a lambda capture is a new feature of C++20

like image 521
wcochran Avatar asked May 04 '18 21:05

wcochran


People also ask

How do you capture variables in lambda?

Capture clause A lambda can introduce new variables in its body (in C++14), and it can also access, or capture, variables from the surrounding scope. A lambda begins with the capture clause. It specifies which variables are captured, and whether the capture is by value or by reference.

Does lambda capture reference by value?

Lambdas always capture objects, and they can do so by value or by reference.

Can lambda function access local variables?

Local variables from outer scope can be captured inside Lambda in 2 modes i.e.

How do you capture a variable in lambda C++?

Much like functions can change the value of arguments passed by reference, we can also capture variables by reference to allow our lambda to affect the value of the argument. To capture a variable by reference, we prepend an ampersand ( & ) to the variable name in the capture.


4 Answers

As cppreference says:

[=] captures all automatic variables used in the body of the lambda by copy and current object by reference if exists

like image 172
bipll Avatar answered Oct 04 '22 11:10

bipll


[=] does what you want -- it captures anything not a member variable by value, and *this by reference (or this by value).

[*this,=] captures both local variables and the object by value in c++17.

[&] captures local variables by reference and *this by reference or this (the pointer) by value.

Both default capture modes capture this the same way. Only in c++17 can you change that.

like image 43
Yakk - Adam Nevraumont Avatar answered Oct 04 '22 13:10

Yakk - Adam Nevraumont


[=] already captures this by value. Take a look at the following code live here: http://cpp.sh/87iw6

#include <iostream>
#include <string>

struct A {
    std::string text;

    auto printer() {
        return [=]() {
            std::cout << this->text << "\n";
        };
    }
};

int main() {
    A a;
    auto printer = a.printer();
    a.text = "Hello, world!";

    printer();
}
like image 30
N00byEdge Avatar answered Oct 04 '22 11:10

N00byEdge


[=] will work, because it captures all automatic variables used in the body of the lambda by copy.

Here is the example output: https://www.ideone.com/kkXvJT

#include <iostream>
#include <functional>

class Foo
{
  int x, y, z;
  std::function<void(void)> _func;

public:
  Foo(int a): x(a), y(0), z(0)  {}

  void bar()
  {
    int a = 1,b,c;
    _func = [=]()
    {
      int u = this->x + a;
      std::cout << u << std::endl;
    };

    _func(); // lambda call
  }
};

int main()
{
  Foo obj(1);
  obj.bar();
}
like image 29
JeJo Avatar answered Oct 04 '22 11:10

JeJo