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