2

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.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • 5
    That's not at all "understandable" to me. Surely that's a bug. All uses of `this` should refer to the capture, not the compiler-generated lambda class, which to the user doesn't exist. I can't replicate with `g++` 9 (no options). It prints `4Bobo`, just like @songyuanyao's tests. – underscore_d Jun 17 '20 at 14:34
  • 4
    Can't reproduce with [clang](https://wandbox.org/permlink/RsnfzLQdaJi0SG3Q) and [gcc](https://wandbox.org/permlink/htcERsFq0TAtLJty). What's your compiler? – songyuanyao Jun 17 '20 at 14:35
  • @songyuanyao I compiled with Visual Studio Community 2019 on Windows. I checked again, that's the result I get. I got the behavior I wanted by creating a local temporary variable and capturing that. Still, this isn't supposed to happen? – Zebrafish Jun 17 '20 at 14:54
  • 1
    Nope, it's wrong. Please file a bug against VS :-) – underscore_d Jun 17 '20 at 15:01

2 Answers2

1

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.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
0

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'; 
einpoklum
  • 118,144
  • 57
  • 340
  • 684