Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ lambda - capture member variable

Tags:

c++

c++11

lambda

I have a class that has function pointer to kernel function, that can change from outside.

class Bar 
{
   public:
     int i;
}

class Foo 
{
   public:
     std::function<double()> kernel;
     Bar bar;         
};

int main()
{

  Foo f;
  f.kernel = []() -> double { return i * i; }; //this is not working obviously

}

How can I achieve behaviour that is "presented", eg. read class variables inside lambda. I can bypass it by passing f inside and write f.bar.i, but that is not very nice solution.

like image 225
Martin Perry Avatar asked Oct 03 '15 11:10

Martin Perry


People also ask

How do you capture a member variable in lambda?

To capture the member variables inside lambda function, capture the “this” pointer by value i.e. std::for_each(vec. begin(), vec. end(), [this](int element){ //.... }

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

Only variables that are mentioned in the lambda body are captured when a capture-default is used. To use lambda expressions in the body of a class member function, pass the this pointer to the capture clause to provide access to the member functions and data members of the enclosing class.

Can you pass local variables to lambda expressions?

A lambda expression can't define any new scope as an anonymous inner class does, so we can't declare a local variable with the same which is already declared in the enclosing scope of a lambda expression. Inside lambda expression, we can't assign any value to some local variable declared outside the lambda expression.

Can lambda access global variables?

The lambda's execution takes place in a fresh local context with only its two local parameter variables, x and y ; it doesn't have access to global variables.


2 Answers

In C++14 you can write it as,

f.kernel = [&i = f.bar.i]() -> double { return i * i; };

If you don't have C++14, you can alternatively create another variable,

int &i = f.bar.i;
f.kernel = [&i]() -> double { return i*i; };

Though there's nothing wrong with passing f and writing f.bar.i.

like image 118
aslg Avatar answered Oct 12 '22 23:10

aslg


It seems that you cannot do so. There is no construct to create a member function lambda.

But you probably can follow @KerrekSB's suggestion and in addition to that dispatch the call to still get the member function:

class Foo 
{
public:
    double kernel()
    {
        _kernel(*this);
    }

    std::function<double(Foo &)> _kernel;
};


Foo f;
f._kernel = [](Foo &f) -> double { return f.i * f.i; };
f.kernel()

Note that you cannot name both fields kernel.

like image 41
dhke Avatar answered Oct 12 '22 23:10

dhke