demote boost::function to a plain function pointer
Has anyone noticed that the accepted answer only works with trivial cases? The only way that function<>::target() will return an object that can be bound to a C callback, is if it was constructed with an object that can be bound to a C callback. If that's the case, then you could have bound it directly and skipped all of the function<> nonsense to begin with.
If you think about it, there isn't any magic solution to this. A C-style callback is stored as a single pointer which points to executable code. Any nontrivial boost::function<> is going to need at least two pointers: one to the executable code, the other to the data that's needed to set up the call (e.g. the 'this' pointer, in the case of a bound member function).
The right way to use boost::function and boost::bind with C callbacks is to create a shim function that satisfies the callback signature, figures out which function<> to call, and calls it. Usually C callbacks will have some kind of a void* for 'user data'; that's where you stash your function pointer:
typedef void (*CallbackType)(int x, void* user_data);
void RegisterCallback(CallbackType cb, void* user_data);
void MyCallback(int x, void* userData) {
boost::function<void(int)> pfn = static_cast<boost::function<void(int)> >(userData);
pfn(x);
}
boost::function<void(int)> fn = boost::bind(myFunction(5));
RegisterCallback(MyCallback, &fn);
Of course, if your callback signature doesn't include some kind of user data pointer, you're out of luck. But any callback that doesn't include a user data pointer is already unusable in most real-world scenarios, and needs to be rewritten.
I think you want to use the target() member function of boost::function (isn't that a mouthful...)
#include <boost/function.hpp>
#include <iostream>
int f(int x)
{
return x + x;
}
typedef int (*pointer_to_func)(int);
int
main()
{
boost::function<int(int x)> g(f);
if(*g.target<pointer_to_func>() == f) {
std::cout << "g contains f" << std::endl;
} else {
std::cout << "g does not contain f" << std::endl;
}
return 0;
}
can you get it working with bind?
cb_t cb = *g.target<cb_t>(); //target returns null
This is by design. Basically, since bind
returns a completely different type, there's no way that this will work. Basically, a binder proxy object cannot be converted to a C function pointer (since it isn't one: it's a function object). The type returned by boost::bind
is complicated. The current C++ standard allows no good way of doing what you want. C++0x will be fitted with a decltype
expression which could be used here to achieve something like this:
typedef decltype(bind(f, 3)) bind_t;
bind_t target = *g.target<bind_t>();
Notice that this might or might not work. I have no way of testing it.
see boost mailing page [boost] [Function] Problem using target() with boost::mem_fn and boost::bind