How to pass a private member function as an argument - c++

In ROS, there is a function called NodeHanle::subscribe(Args...): NodeHandle::subscribe. Which lets u pass a PRIVATE member function as callback.
However, when I tried it myself (passing private member function using std::bind), my compiler always fails and complaining about Foo::foo() is a private member function. When I change Foo::foo to public function, everything goes to normal.
template<typename T>
void getWrapper1(void(T::*fn)(int), T *t) {
return [&](int arg) {
std::cout << "process before function with wrapper" << std::endl;
(t->*fn)(arg);
std::cout << "process after function with wrapper" << std::endl;
};
}
void getWrapper2(std::function<void(int)> fn) {
return [=](int arg) {
std::cout << "process before function with wrapper" << std::endl;
fn(arg);
std::cout << "process after function with wrapper" << std::endl;
}
}
class Foo {
private:
void foo(int a) {
std::cout << __FUNCTION__ << a << std::endl;
}
}
int main(int argc, char** argv) {
Foo foo_inst;
auto func1 = getWrapper1(&Foo::foo, &foo_inst); // fail because foo is private
auto func2 = getWrapper2(std::bind(&Foo::foo, &foo_inst, std::placeholders::_1)); // fail because foo is private
func1(1);
func2(2);
return 0;
}
from this answer, using std::function can also passing private member function. But what I tried it different.
It worths to mention that in getWrapper2 I use [=] instead of [&] because using [&] may cause seg fault. Why it has to be a "value capture"?
platform: GCC 5.4.0, c++14, ubuntu16.04

You must pass it from the inside. You cannot access private function from the outside of the class. Not even pointer to private stuff. Private is private.
class Foo {
void foo(int a) {
std::cout << __FUNCTION__ << a << std::endl;
}
public:
auto getWrapper() {
// using a lambda (recommended)
return getWrapper2([this](int a) {
return foo(a);
});
// using a bind (less recommended)
return getWrapper2(std::bind(&Foo::foo, this, std::placeholders::_1));
}
}
Why it has to be a "value capture"?
Both wrapper need to value capture. Your Wrapper1 have undefined behaviour.
Consider this:
// returns a reference to int
auto test(int a) -> int& {
// we return the local variable 'a'
return a;
// a dies when returning
}
The same thing happen with a lambda:
auto test(int a) {
// we capture the local variable 'a'
return [&a]{};
// a dies when returning
}
auto l = test(1);
// l contain a captured reference to 'a', which is dead
Pointers are passed by value. A pointer is itself an object. A pointer has itself a lifetime and can die.
auto test(int* a) -> int*& {
// we are still returning a reference to local variable 'a'.
return a;
}
And... you guessed it, the same thing for std::function:
auto test(std::function<void(int)> a) {
// return a lambda capturing a reference to local variable 'a'.
return [&a]{};
}

Related

Lambda as "member" when class instance is captured

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);
}

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

lambda capture of std function

The following code causes segmentation fault, but I can't understand why:
#include <iostream>
#include <vector>
#include <functional>
class State {public:int x; int y; State(int _x,int _y):x(_x),y(_y){}};
typedef std::function<bool (const State &s)> FuncT;
std::vector<FuncT> funcs_outside;
class Manager
{
private: std::vector<FuncT> funcs;
public: void insert(const FuncT &g){funcs.push_back(g);}
// public: void insert(const FuncT &g){funcs_outside.push_back(g);}
public: FuncT getAnd()
{
// this should capture everything, no?
return [=](const State &s)
{
bool b=true;
for (const auto f:funcs)
// for (const auto f:funcs_outside)
{
b = b && f(s);
}
return b;
};
}
};
FuncT foo(void)
{
Manager m;
m.insert([=](const State &s){return s.x<=s.y;});
m.insert([=](const State &s){return s.x>=s.y;});
return m.getAnd();
}
int main(int argc, char **argv)
{
auto h = foo();
std::cout << "h(3,3) = " << h(State(3,3)) << "\n";
std::cout << "h(3,4) = " << h(State(3,4)) << "\n";
std::cout << "h(7,2) = " << h(State(7,2)) << "\n";
return 0;
}
The [=] should capture anything the lambda needs right?
When I replace funcs with funcs_outside, everything works well.
What am I doing wrong?
What am I doing wrong?
getAnd returns a function object from a member function, which captures and accesses members.
You call that member function on a local variable, and return the resulting function object to the outside of the scope. The members pointed by the function object no longer exist and calling the function object results in undefined behaviour.
When I replace funcs with funcs_outside, everything works well.
funcs_outside is a global object and you access it within its lifetime, so there is no problem.
how can I fix this?
You could for example capture a copy of the member instead:
return [funcs = this->funcs](const State &s)

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);
}
}