How can I access the `typeid` of a captured this pointer in a lambda?

Viewed 97

I have the following code:

#include <iostream>

class Bobo
{public:
    int member;
    void function()
    {
        auto lambda = [this]() { std::cout << member << '\n'; };
        auto lambda2 = [this]() { std::cout << typeid(*this).name() << '\n'; };
        lambda();
        lambda2();
    }
};

int main()
{
    Bobo bobo;
    bobo.function();
}

The line std::cout << typeid(*this).name(); in lambda2() understandably prints out:

class <lambda_49422032c40f80b55ca1d0ebc98f567f>

However how can I access the 'this' pointer that's been captured so the typeid operator can return type class Bobo?

Edit: The result I get is from compiling this code in Visual Studio Community 2019.

2 Answers

This seems to be VS's bug; when determining the type of this pointer in lambda:

For the purpose of name lookup, determining the type and value of the this pointer and for accessing non-static class members, the body of the closure type's function call operator is considered in the context of the lambda-expression.

struct X {
    int x, y;
    int operator()(int);
    void f()
    {
        // the context of the following lambda is the member function X::f
        [=]()->int
        {
            return operator()(this->x + y); // X::operator()(this->x + (*this).y)
                                            // this has type X*
        };
    }
};

So the type of this should be Bobo* in the lambda.

As @songyuanyao suggests, your could should work and produce the appropriate typeid, so it's probably a bug. But - here's a workaround for you:

#include <iostream>

class Bobo
{public:
    int member;
    void function() {
        auto lambda = [this]() { std::cout << member << '\n'; };
        auto lambda2 = [my_bobo = this]() { 
            std::cout << typeid(std::decay_t<decltype(*my_bobo)>).name() << '\n'; 
        };
        lambda();
        lambda2();
    }
};

int main() {
    Bobo bobo;
    bobo.function();
}

Note that you can replaced typeid(...).name() with the proper type name, obtained (at compile-time!) as per this answer:

std::cout << type_name<std::decay_t<decltype(*my_bobo)>>() << '\n'; 
Related