How to properly do callbacks to C++ member functions is something that has intrigued me for some time now. There are a number of solutions, none of which I really liked. But now with the std::tr1::function and std::tr1::bind functions, there appears to be a clean solution.
In the past, if you wanted a callback to a C++ member function a typical approach was to create a static function wrapper as described here. However, this is ugly, and a step backwards from the capabilities of plain old C.
std::tr1::function is a function wrapper that can be used to create function objects for a number of scenarios. We are interested in representing class member functions.
#include <tr1/functional> struct X { int foo(int); }; std::tr1::function<int (X*, int)> f; f = &X::foo; X x; f(&x, 6);
f() is now a simple function representation that can be passed around, etc. However, what we don’t like is the reference to the struct X type, which makes it much less generic. This is where the std::tr1::bind function comes in. With bind, we can dynamically bind one function to another, and re-arrange the arguments, etc. So to make a generic portable function that points to X::foo(), we can do something like the following.
#include <tr1/functional> struct X { int foo(int); }; std::tr1::function<int (int)> f; X x; f = std::tr1::bind(&X::foo, &x, _1); f(6);
Now, f() is a very generic function that could be used in various interfaces without specifically referencing struct X.
A more complete example of how callbacks might work is given below:
#include <iostream> #include <tr1/functional> struct B { std::tr1::function <void ()> _callback; void reg_callback(std::tr1::function <void ()> callback) { _callback = callback; } void unreg_callback() { _callback = NULL; } void process() { // simply calls callback if (_callback) _callback(); } }; struct A { B * _b; A(B * b) : _b(b) { std::tr1::function<void()> callback; callback = std::tr1::bind(&A::callback, this); b->reg_callback(callback); } ~A() { _b->unreg_callback(); } void callback() { std::cout << "A::callback called\n"; } void process() { _b->process(); } }; int main() { B * b = new B(); A * a = new A(b); // the following is example where object b calls // back into a method // in object a a->process(); // now delete object a, and verify the callback // in B does not crash or still get called delete a; // now b should not execute the callback b->process(); }
In the above example, the callback in the object a will be called once.