Reputation: 1475
This may have been explored before, but I am not certain how it works out, and how t should in my particular case..
Essentially I have a class, with a callback defined as :
class Foo
{
public:
using someCallbackName = std::function<void(int)>;
void someFunc();
Foo(int, someCallBackName);
private :
someCallbackName m_callBack;
}
void Foo::someFunc()
{
m_callBack(1);
}
I used to call this in main()
or by just referencing function of similar signature..
void someOtherFunction(int x)
{
cout << x;
}
int main()
{
Foo::someCallbackName callBack = someOtherFunction;
Foo foo(5, callBack);
}
I decided though, that I may need someOtherFunction
as a class member, and put it as part of a class. However, using class member function someOtherFunction
as a callback required making it static, which worked fine, but which would mean it wouldn't have access to non-static class members, which sort of defeated the purpose to put it in a class.
I tried using : C++ callback using class member
and the struct access as given in : https://en.cppreference.com/w/cpp/utility/functional/bind
..but it does not seem to work, the std::bind to
Foo::someCallbackName callBack = std::bind(not_sure_what_to_use_here);
keeps giving errors saying no suitable conversion, which makes me think that somewhere the signature of callback or mechanism of using std::bind
in the code is erroneous.
Keeping class Foo
as is, how can m_callBack
call someOtherFunction
?
Upvotes: 2
Views: 4535
Reputation: 2070
As @Daniel Langr said, you can use a lambda function.
Otherwise if you want to use a callback that is a member function you need to bind it to an object.
#include <functional>
#include <iostream>
class Foo
{
public:
using someCallbackName = std::function<void(int)>;
void someFunc();
Foo(int, someCallbackName);
private:
someCallbackName m_callBack;
};
class Bar
{
public:
void someOtherFunction(int x);
};
Foo::Foo(int i, someCallbackName cb)
{
m_callBack = cb;
someFunc();
}
void Foo::someFunc()
{
m_callBack(1);
}
void Bar::someOtherFunction(int x)
{
std::cout << x;
}
int main()
{
Bar bar;
Foo::someCallbackName callBack = std::bind(&Bar::someOtherFunction, &bar, std::placeholders::_1);
Foo foo(5, callBack);
}
Be careful about the lifetime of bar
when doing this.
Oone way to adress the lifetime issue is to make Foo
responsible for the lifetime of Bar
(this design pattern is called a composition).
#include <functional>
#include <iostream>
// If you declare both class in different files you may need to look into "forward declaration"
class Bar
{
public:
void someOtherFunction(int x);
};
class Foo
{
public:
using someCallbackName = std::function<void(int)>;
void someFunc();
Foo(int, someCallbackName);
private:
someCallbackName m_callBack;
Bar bar;
};
Foo::Foo(int i)
{
m_callBack = std::bind(&Bar::someOtherFunction, &bar, std::placeholders::_1);;
someFunc();
}
// someOtherFunction and someFunc are left unchanged
int main()
{
Foo foo(5);
}
Upvotes: 1
Reputation: 23497
You can "bind" the callback to a non-static member function of a particular object by using labmda:
class X {
public:
void someOtherFunction(int x) const { std::cout << x; }
};
int main()
X x;
Foo::someCallbackName callBack = [&x](int i){ x.someOtherFunction(i); };
Foo foo(5, callBack);
foo.someFunc();
}
Live demo: https://wandbox.org/permlink/fUmrnD6xn1xr7zn0.
To avoid dangling references after x
is destroyed, you can employ shared pointers, as follows (note it is captured by value):
Foo::someCallbackName callBack;
{
auto ptr_x = std::make_shared<X>();
callBack = [ptr_x](int i){ ptr_x->someOtherFunction(i); };
}
Foo foo(5, callBack);
foo.someFunc();
Live demo: https://wandbox.org/permlink/23euPcuDUsDENdRe.
Upvotes: 2