Call a std::function class member with std::mem_fn - c++

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

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 to pass a private member function as an argument

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]{};
}

What is the advantage of storing a lambda in a `std::function` as opposed to an `auto variable`?

What is the advantage of storing a lambda in a std::function as opposed to an auto variable. For example in the code below I store the lambda in variable f1 rather than in std::function f.
#include <iostream>
#include <functional>
using namespace std;
void global_f() {
cout << "global_f()" << endl;
}
struct Functor {
void operator()() { cout << "Functor" << endl; }
};
int main() {
std::function<void()> f;
cout << "sizeof(f) == " << sizeof(f) << endl;
f = global_f;
f();
auto f1 = [](){ cout << "Lambda" << endl;};
f1();
Functor functor;
f = functor;
f();
}
In your simple example, there is no advantage to storing the lambda inside a std::function. Often, storing a lambda using auto is more efficient, but it also highly restrictive. The auto version can serve only as a local variable. If you want to store the lambda for later use, then you must use a std::function.
For example, you might want to store the lambda inside a class member. Consider the following class:
class Foo
{
std::function<void()> callback_;
public:
void Bar(int value)
{
callback_ = [value] { DoStuff(value); }
}
/* other constructors and methods omitted */
}
In this case, you can't use auto because the lambda's type is anonymous and only available within the Bar method.
std::function is also useful when you want to use lambdas as arguments to regular functions. The function has no way to know the lambda's type, but it can declare a std::function parameter instead. For example:
void Foo(std::function<void()> callback);
...
Foo([](){ cout << "Lambda" << endl;});
It's worth pointing out that this does not apply to function templates. When using a lambda in such a context, it's usually a better idea to let the compiler deduce the lambda's type (similar to using auto). For example:
template <class F> void Foo(F&& callback) { /* details */ }
...
Foo([](){ cout << "Lambda" << endl;}

Can I store bound functions in a container?

Consider the following code:
void func_0()
{
std::cout << "Zero parameter function" << std::endl;
}
void func_1(int i)
{
std::cout << "One parameter function [" << i << "]" << std::endl;
}
void func_2(int i, std::string s)
{
std::cout << "One parameter function [" << i << ", " << s << "]" << std::endl;
}
int main()
{
auto f0 = boost::bind(func_0);
auto f1 = boost::bind(func_1,10);
auto f2 = boost::bind(func_2,20,"test");
f0();
f1();
f2();
}
The above code works as intended. Is there any way I can store f0, f1, f2 in a container and execute it like this:
Container cont; // stores all the bound functions.
for(auto func : cont)
{
func();
}
Will this example work for you?
std::vector<std::function<void()>> container{f0, f1, f2};
for (auto& func : container)
{
func();
}
You can read here about std::function:
Instances of std::function can store, copy, and invoke any Callable
target ...
So the template argument for this class template (void() in our case) is merely the signature of the Callable. What bind() returned in all your calls to it is exactly a Callable of the form void().
std::bind is not guaranteed to return the same type for functions with the same final interface (final = after binding). So, no, you won't be able to store functions bound with std::bind in a container. You will have to use some sort of type-erasure technique to bring them all to the same type, like std::function. A container of std::function<void()> will be able to store your bound functions (at the expense of type-erasure-related overhead).
I don't know whether it applies to boost::bind, but I suspect it is the same as std::bind in that regard.

C++11 styled callbacks?

I have a void function inside of a class. In old C++ i'd make a function static taking the class name as a parameter and had my own class which took a static void function + a void* for me to easily call it.
However that feels old school. It also isn't templated which feels like i could be doing more. What is a more modern way of creating callbacks to myclassVar.voidReturnVoidParamFunc
Use std::function and lambdas (or std::bind()) to store callables:
#include <functional>
#include <iostream>
class Test
{
public:
void blah() { std::cout << "BLAH!" << std::endl; }
};
class Bim
{
public:
void operator()(){ std::cout << "BIM!" << std::endl; }
};
void boum() { std::cout << "BOUM!" << std::endl; }
int main()
{
// store the member function of an object:
Test test;
std::function< void() > callback = std::bind( &Test::blah, test );
callback();
// store a callable object (by copy)
callback = Bim{};
callback();
// store the address of a static function
callback = &boum;
callback();
// store a copy of a lambda (that is a callable object)
callback = [&]{ test.blah(); }; // often clearer -and not more expensive- than std::bind()
callback();
}
Result:
BLAH!
BIM!
BOUM!
BLAH!
Compiles and run: http://ideone.com/T6wVp
std::function can be used as any copyiable object, so feel free to store it somewhere as a callback, like in object's member. It also means that you can freely put it in standard containers, like std::vector< std::function< void () > > .
Also note that equivalent boost::function and boost::bind have been available for years.
For an example of passing in parameters to a C++ 11 callback using Lambda's and a vector, see http://ideone.com/tcBCeO or below:
class Test
{
public:
Test (int testType) : m_testType(testType) {};
void blah() { std::cout << "BLAH! " << m_testType << std::endl; }
void blahWithParmeter(std::string p) { std::cout << "BLAH1! Parameter=" << p << std::endl; }
void blahWithParmeter2(std::string p) { std::cout << "BLAH2! Parameter=" << p << std::endl; }
private:
int m_testType;
};
class Bim
{
public:
void operator()(){ std::cout << "BIM!" << std::endl; }
};
void boum() { std::cout << "BOUM!" << std::endl; }
int main()
{
// store the member function of an object:
Test test(7);
//std::function< void() > callback = std::bind( &Test::blah, test );
std::function< void() > callback = std::bind( &Test::blah, test );
callback();
// store a callable object (by copy)
callback = Bim{};
callback();
// store the address of a static function
callback = &boum;
callback();
// store a copy of a lambda (that is a callable object)
callback = [&]{ test.blah(); }; // might be clearer than calling std::bind()
callback();
// example of callback with parameter using a vector
typedef std::function<void(std::string&)> TstringCallback;
std::vector <TstringCallback> callbackListStringParms;
callbackListStringParms.push_back( [&] (const std::string& tag) { test.blahWithParmeter(tag); });
callbackListStringParms.push_back( [&] (const std::string& tag) { test.blahWithParmeter2(tag); });
std::string parm1 = "parm1";
std::string parm2 = "parm2";
int i = 0;
for (auto cb : callbackListStringParms )
{
++i;
if (i == 1)
cb(parm1);
else
cb(parm2);
}
}