Ziming Song
Ziming Song

Reputation: 1346

C++11 variable capture with lambda inside another lambda

In node.js I can write lambda inside lambda and capture whichever variable I want. But in C++11, as lambda functions are actually functor object, variable capturing is not so easy with nested lambdas.

I'm using [this] to capture this pointer so I can use class members. But inside a lambda, this pointer points to the lambda instead of the outter class.

void MyClass::myFunction() {
    // call the lambda1
    connect(action, trigger, [this]() {
        // in the lambda1, call lambda2
        sendCommand([this]() {      // <-- I want `this` point to the outter class
            this->myMember.log("something");  // myMember is the member of class MyClass
        });
    });
}

I know it can be done by rename this to another pointer variable and capture that variable instead of this, but I think that way is ugly.

Is there any better way to capture outter this?

Upvotes: 2

Views: 14541

Answers (2)

Casey
Casey

Reputation: 42554

But inside a lambda, this pointer points to the lambda instead of the outter class.

No, inside the lambda this has the same value as outside. The only problem in your code is accessing this with . instead of ->. This program:

void MyClass::myFunction() {
    std::cout << this << std::endl;
    // call the lambda1
    connect(action, trigger, [this]() {
        std::cout << this << std::endl;
        // in the lambda1, call lambda2
        sendCommand([this]() {      // <-- I want `this` point to the outter class
            std::cout << this << std::endl;
            this->myMember.log("something");  // myMember is the member of class MyClass
        });
    });
}

Prints the same value for this in all three places:

g++ -std=c++11 -O3 -Wall -Wextra -pedantic -pthread main.cpp && ./a.out
0x7fff4286c80f
0x7fff4286c80f
0x7fff4286c80f

N3936 (C++14 Working Draft) [expr.prim.lambda]/18 states:

Every id-expression within the compound-statement of a lambda-expression that is an odr-use (3.2) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [ Note: An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type. Furthermore, such an id-expression does not cause the implicit capture of the entity. —end note ] If this is captured, each odr-use of this is transformed into an access to the corresponding unnamed data member of the closure type, cast (5.4) to the type of this. [ Note: The cast ensures that the transformed expression is a prvalue. —end note ]

Upvotes: 3

nurettin
nurettin

Reputation: 11736

You simply capture outer lambda's context:

#include <iostream>

struct Omg
{
  int lol= 42;

  Omg()
  {
    [this]{ [&]{ std::cout<< this-> lol; }(); }();
  }
};

int main(){ Omg(); }

Upvotes: 3

Related Questions