Lambda as "member" when class instance is captured - c++

The question title might not be the most clear one, but here is the explanation:
Basically I want to call a member function to which I pass a lambda, and I want to access class members from the lambda like if the lambda itself was a class member.
I came up with this code which works as expected but which does not exactly what I want.
#include <iostream>
class MyClass
{
int member = 123;
public:
void SomeFunction()
{
std::cout << "SomeFunction()\n";
}
template<typename Functor>
void Test(Functor functor, int val)
{
functor();
std::cout << val << " " << member;
}
};
int main()
{
MyClass instance;
instance.Test([&instance] {std::cout << "Lambda\n"; instance.SomeFunction(); }, 42);
}
There are two things that bother me:
in the lambda I need to mention explicitly the captured class instance.
but more importantly: in the lambda there is no way to access private class members
I'd like to be able to write:
{std::cout << "Lambda\n"; instance.SomeFunction(); }
instead of:
{std::cout << "Lambda\n"; SomeFunction(); }
and even:
{std::cout << "Lambda\n"; instance.member; } // access private members from lambda
Is there some way to do this?

This works with GCC 10.3 using --std=c++20. Instead of capturing the instance when defining your lambda just pass it to the functor as a reference (this way you can reuse it). As for accessing private members just forget about it, it's not worth the time, and defeats the meaning of private. Just make the member public.
Passing the functor as a non-type template argument is optional (it could be a function argument, avoiding the need for C++20)
#include <iostream>
class MyClass
{
public:
int member = 123;
void SomeFunction()
{
std::cout << "SomeFunction()\n";
}
template<auto functor>
void Test(int val)
{
functor(*this);
std::cout << val << " " << member << std::endl;
}
};
int main()
{
MyClass instance;
auto lambda = [](auto& _instance) {std::cout << "Lambda\n"; _instance.SomeFunction(); };
instance.Test<lambda>(42);
}

Related

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

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.
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';

How to write a constructor for non-named class [duplicate]

Is there a way to declare a constructor or a destructor in an unnamed class? Consider the following
void f()
{
struct {
// some implementation
} inst1, inst2;
// f implementation - usage of instances
}
Follow up question : The instances are ofcourse constructed (and destroyed) as any stack based object. What gets called? Is it a mangled name automatically assigned by the compiler?
The simplest solution is to put a named struct instance as a member in the unnamed one, and put all of the functionality into the named instance. This is probably the only way that is compatible with C++98.
#include <iostream>
#include <cmath>
int main() {
struct {
struct S {
double a;
int b;
S() : a(sqrt(4)), b(42) { std::cout << "constructed" << std::endl; }
~S() { std::cout << "destructed" << std::endl; }
} s;
} instance1, instance2;
std::cout << "body" << std::endl;
}
Everything that follows requires C++11 value initialization support.
To avoid the nesting, the solution for the construction is easy. You should be using C++11 value initialization for all members. You can initialize them with the result of a lambda call, so you can really execute arbitrarily complex code during the initialization.
#include <iostream>
#include <cmath>
int main() {
struct {
double a { sqrt(4) };
int b { []{
std::cout << "constructed" << std::endl;
return 42; }()
};
} instance1, instance2;
}
You can of course shove all the "constructor" code to a separate member:
int b { [this]{ constructor(); return 42; }() };
void constructor() {
std::cout << "constructed" << std::endl;
}
This still doesn't read all that cleanly, and conflates the initialization of b with other things. You could move the constructor call to a helper class, at the cost of the empty class still taking up a bit of space within the unnamed struct (usually one byte if it's the last member).
#include <iostream>
#include <cmath>
struct Construct {
template <typename T> Construct(T* instance) {
instance->constructor();
}
};
int main() {
struct {
double a { sqrt(4) };
int b { 42 };
Construct c { this };
void constructor() {
std::cout << "constructed" << std::endl;
}
} instance1, instance2;
}
Since the instance of c will use some room, we might as well get explicit about it, and get rid of the helper. The below smells of a C++11 idiom, but is a bit verbose due to the return statement.
struct {
double a { sqrt(4) };
int b { 42 };
char constructor { [this]{
std::cout << "constructed" << std::endl;
return char(0);
}() };
}
To get the destructor, you need the helper to store both the pointer to an instance of the wrapped class, and a function pointer to a function that calls the destructor on the instance. Since we only have access to the unnamed struct's type in the helper's constructor, it's there that we have to generate the code that calls the destructor.
#include <iostream>
#include <cmath>
struct ConstructDestruct {
void * m_instance;
void (*m_destructor)(void*);
template <typename T> ConstructDestruct(T* instance) :
m_instance(instance),
m_destructor(+[](void* obj){ static_cast<T*>(obj)->destructor(); })
{
instance->constructor();
}
~ConstructDestruct() {
m_destructor(m_instance);
}
};
int main() {
struct {
double a { sqrt(4) };
int b { 42 };
ConstructDestruct cd { this };
void constructor() {
std::cout << "constructed" << std::endl;
}
void destructor() {
std::cout << "destructed" << std::endl;
}
} instance1, instance2;
std::cout << "body" << std::endl;
}
Now you're certainly complaining about the redundancy of the data stored in the ConstructDestruct instance. The location where the instance is stored is at a fixed offset from the head of the unnamed struct. You can obtain such offset and wrap it in a type (see here). Thus we can get rid of the instance pointer in the ConstructorDestructor:
#include <iostream>
#include <cmath>
#include <cstddef>
template <std::ptrdiff_t> struct MInt {};
struct ConstructDestruct {
void (*m_destructor)(ConstructDestruct*);
template <typename T, std::ptrdiff_t offset>
ConstructDestruct(T* instance, MInt<offset>) :
m_destructor(+[](ConstructDestruct* self){
reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(self) - offset)->destructor();
})
{
instance->constructor();
}
~ConstructDestruct() {
m_destructor(this);
}
};
#define offset_to(member)\
(MInt<offsetof(std::remove_reference<decltype(*this)>::type, member)>())
int main() {
struct {
double a { sqrt(4) };
int b { 42 };
ConstructDestruct cd { this, offset_to(cd) };
void constructor() {
std::cout << "constructed " << std::hex << (void*)this << std::endl;
}
void destructor() {
std::cout << "destructed " << std::hex << (void*)this << std::endl;
}
} instance1, instance2;
std::cout << "body" << std::endl;
}
Unfortunately, it doesn't seem possible to get rid of the function pointer from within ConstructDestruct. This isn't that bad, though, since its size needs to be non-zero. Whatever is stored immediately after the unnamed struct is likely to be aligned to a multiple of a function pointer size anyway, so there may be no overhead from the sizeof(ConstructDestruct) being larger than 1.
You can not declare a constructor or destructor for an unnamed class because the constructor and destructor names need to match the class name. In your example, the unnamed class is local. It has no linkage so neither mangled name is created.
If you are thinking of C++ names, then any class that has objects has to have a destructor whether you create it explicitly or not. So yes, the compiler knows how to assign a name. Whether that naming convention is any of your business, however, probably not.
Actually, you can create a structure or also a namespace without a name. You still need to have names somewhere because at the time you link all of that, the linker needs some kind of a name to make it all work, although in many cases it will be local names that are resolved immediately at compile time--by the assembler.
One way to know of the names assigned by the compiler is to look at the debug strings and see what corresponds to the different addresses that you're interested in. When you compile with -g then you should get all the necessary debug for your debugger to place your current at the right place with the right "names"... (I've see the namespaces without a name it says " namespace", I'm pretty sure structures use the same trick at a higher level.)

Detect/get captured values of a lambda function

Is there a way to detect and/or retrieve the values captured in a lambda function, statically or dynamically ?
Example, for the use case :
randomFunction([this](){ methodCall(); });
Is this possible ?
void randomFunction(std::function<void()> lambda) {
... // Detect if lambda capture is 'this'
MyClass* obj = /* retrieve lambda capture 'this' */;
...
}
Let's say MyClass is known, will always be the same, and all of this occurs in a template function. Is there at least some traits/tricks to distinguish which template function to call according to the lambda captures ?
You have captured this, so why not just return it from the lambda? Of course chaos will ensue if the corresponding object is not accessible anymore.
#include <iostream>
#include <functional>
class MyClass;
void randomFunction(std::function<MyClass*()> lambda)
{
std::cout << __PRETTY_FUNCTION__ << '\n';
MyClass* obj = lambda();
}
class MyClass
{
public:
void methodCall()
{
std::cout << __PRETTY_FUNCTION__ << '\n';
}
void test()
{
std::cout << __PRETTY_FUNCTION__ << '\n';
auto lambda = [this]() { methodCall(); return this; };
randomFunction(lambda);
}
};
int main()
{
MyClass mc;
mc.test();
}
Live example

Call a std::function class member with std::mem_fn

My plan is to build several listener classes which own predefined "callback hooks".
In the example below class Foo has a "callback hook" called onChange. It will be set to a default callback function during construction. It can also be set to an arbitrary function which provides the correct interface, like shown with the object f1 and the function callback().
The problem is when I want to call the object member onChange inside the for-loop the compiler says that I provide to much arguments. i am aware of the problem that i don't provide a member function to the std::mem_fn but instead an object member which is a function wrapper.
How do I manage to pass the argument to the std::function member object of class Foo without using std::bind and use std::mem_fn instead like shown in the example?
struct Foo
{
Foo()
{
// default callback
onChange = [](int value)
-> void { std::cerr << "Foo::onChange( " << value << " )" << std::endl; };
}
// class destructor
virtual ~Foo() {}
std::function<void(int value)> onChange;
};
void callback(int value)
{
std::cerr << "callback( " << value << " )" << std::endl;
}
int main()
{
Foo f0;
Foo f1;
f1.onChange = callback;
auto vec = std::vector<Foo>();
vec.push_back(f0);
vec.push_back(f1);
auto func_wrapper = std::mem_fn( &Foo::onChange );
for (auto f : vec)
{
func_wrapper(f, 42);
}
}

How to add constructors/destructors to an unnamed class?

Is there a way to declare a constructor or a destructor in an unnamed class? Consider the following
void f()
{
struct {
// some implementation
} inst1, inst2;
// f implementation - usage of instances
}
Follow up question : The instances are ofcourse constructed (and destroyed) as any stack based object. What gets called? Is it a mangled name automatically assigned by the compiler?
The simplest solution is to put a named struct instance as a member in the unnamed one, and put all of the functionality into the named instance. This is probably the only way that is compatible with C++98.
#include <iostream>
#include <cmath>
int main() {
struct {
struct S {
double a;
int b;
S() : a(sqrt(4)), b(42) { std::cout << "constructed" << std::endl; }
~S() { std::cout << "destructed" << std::endl; }
} s;
} instance1, instance2;
std::cout << "body" << std::endl;
}
Everything that follows requires C++11 value initialization support.
To avoid the nesting, the solution for the construction is easy. You should be using C++11 value initialization for all members. You can initialize them with the result of a lambda call, so you can really execute arbitrarily complex code during the initialization.
#include <iostream>
#include <cmath>
int main() {
struct {
double a { sqrt(4) };
int b { []{
std::cout << "constructed" << std::endl;
return 42; }()
};
} instance1, instance2;
}
You can of course shove all the "constructor" code to a separate member:
int b { [this]{ constructor(); return 42; }() };
void constructor() {
std::cout << "constructed" << std::endl;
}
This still doesn't read all that cleanly, and conflates the initialization of b with other things. You could move the constructor call to a helper class, at the cost of the empty class still taking up a bit of space within the unnamed struct (usually one byte if it's the last member).
#include <iostream>
#include <cmath>
struct Construct {
template <typename T> Construct(T* instance) {
instance->constructor();
}
};
int main() {
struct {
double a { sqrt(4) };
int b { 42 };
Construct c { this };
void constructor() {
std::cout << "constructed" << std::endl;
}
} instance1, instance2;
}
Since the instance of c will use some room, we might as well get explicit about it, and get rid of the helper. The below smells of a C++11 idiom, but is a bit verbose due to the return statement.
struct {
double a { sqrt(4) };
int b { 42 };
char constructor { [this]{
std::cout << "constructed" << std::endl;
return char(0);
}() };
}
To get the destructor, you need the helper to store both the pointer to an instance of the wrapped class, and a function pointer to a function that calls the destructor on the instance. Since we only have access to the unnamed struct's type in the helper's constructor, it's there that we have to generate the code that calls the destructor.
#include <iostream>
#include <cmath>
struct ConstructDestruct {
void * m_instance;
void (*m_destructor)(void*);
template <typename T> ConstructDestruct(T* instance) :
m_instance(instance),
m_destructor(+[](void* obj){ static_cast<T*>(obj)->destructor(); })
{
instance->constructor();
}
~ConstructDestruct() {
m_destructor(m_instance);
}
};
int main() {
struct {
double a { sqrt(4) };
int b { 42 };
ConstructDestruct cd { this };
void constructor() {
std::cout << "constructed" << std::endl;
}
void destructor() {
std::cout << "destructed" << std::endl;
}
} instance1, instance2;
std::cout << "body" << std::endl;
}
Now you're certainly complaining about the redundancy of the data stored in the ConstructDestruct instance. The location where the instance is stored is at a fixed offset from the head of the unnamed struct. You can obtain such offset and wrap it in a type (see here). Thus we can get rid of the instance pointer in the ConstructorDestructor:
#include <iostream>
#include <cmath>
#include <cstddef>
template <std::ptrdiff_t> struct MInt {};
struct ConstructDestruct {
void (*m_destructor)(ConstructDestruct*);
template <typename T, std::ptrdiff_t offset>
ConstructDestruct(T* instance, MInt<offset>) :
m_destructor(+[](ConstructDestruct* self){
reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(self) - offset)->destructor();
})
{
instance->constructor();
}
~ConstructDestruct() {
m_destructor(this);
}
};
#define offset_to(member)\
(MInt<offsetof(std::remove_reference<decltype(*this)>::type, member)>())
int main() {
struct {
double a { sqrt(4) };
int b { 42 };
ConstructDestruct cd { this, offset_to(cd) };
void constructor() {
std::cout << "constructed " << std::hex << (void*)this << std::endl;
}
void destructor() {
std::cout << "destructed " << std::hex << (void*)this << std::endl;
}
} instance1, instance2;
std::cout << "body" << std::endl;
}
Unfortunately, it doesn't seem possible to get rid of the function pointer from within ConstructDestruct. This isn't that bad, though, since its size needs to be non-zero. Whatever is stored immediately after the unnamed struct is likely to be aligned to a multiple of a function pointer size anyway, so there may be no overhead from the sizeof(ConstructDestruct) being larger than 1.
You can not declare a constructor or destructor for an unnamed class because the constructor and destructor names need to match the class name. In your example, the unnamed class is local. It has no linkage so neither mangled name is created.
If you are thinking of C++ names, then any class that has objects has to have a destructor whether you create it explicitly or not. So yes, the compiler knows how to assign a name. Whether that naming convention is any of your business, however, probably not.
Actually, you can create a structure or also a namespace without a name. You still need to have names somewhere because at the time you link all of that, the linker needs some kind of a name to make it all work, although in many cases it will be local names that are resolved immediately at compile time--by the assembler.
One way to know of the names assigned by the compiler is to look at the debug strings and see what corresponds to the different addresses that you're interested in. When you compile with -g then you should get all the necessary debug for your debugger to place your current at the right place with the right "names"... (I've see the namespaces without a name it says " namespace", I'm pretty sure structures use the same trick at a higher level.)