2

I have a C library function with the following signature,

void register_callback(void (*callback)(int, void*), void* args);

What is the best way to get this to work with, if I have a callback of the form,

std::function<void(int)>?
vikky.rk
  • 3,989
  • 5
  • 29
  • 32
  • Maybe [this](http://stackoverflow.com/questions/10938774/get-function-pointer-from-stdfunction-when-using-stdbind) helps. – cadaniluk Nov 04 '15 at 19:34
  • I assume that `void* args` is for userdata, that you can cast back to your type. – Jarod42 Nov 04 '15 at 19:37
  • 2
    Is your register callback **actually** `void register_callback(void(*callback)(void*,int), void* args)` by any chance? If yes, please correct. If no, please provide more information on how the callback works, and what the arguments mean. Ideally actually copy-paste the actual callback interface here, don't paraphrase. – Yakk - Adam Nevraumont Nov 04 '15 at 19:37
  • @Jarod42 yes it is for userdata – vikky.rk Nov 04 '15 at 19:39
  • Avoid std:::function (If you bind to a class, have a static function dispatching to a member-function, where `args` represents the class object) –  Nov 04 '15 at 19:42
  • @Yakk you are right. Updated. – vikky.rk Nov 04 '15 at 19:46

2 Answers2

3
std::function<void(int)> bob;
register_callback( [](int x, void* pbob){
  auto& bob = *static_cast<std::function<void(int)>*>(pbob);
  bob(x);
}, &bob );

this remains valid for as long as the variable bob does.

A copy of bob is not enough, the actual instance of bob that we took a pointer to in the register_callback call has to live long enough.

If this is difficult, consider a smart pointer wrapping said std::function and doing a pointer to the stored std::function.

There will be modest overhead in the above, in that we dispatch over a function pointer, then over the equivalent of a vtable, then inside the std::function again.

What is going on above is that I make a stateless lambda to convert the void* args into a pointer-to-std::function, and invoke that std::function with the int. Stateless lambdas can convert to function pointers implicitly.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Thanks. Can you elaborate a little more on your suggestion of using smart pointer? Did you mean to create a std::function object on heap and wrap it with a smart pointer? But then I would have to ensure that the the smart pointer remains valid right? – vikky.rk Nov 04 '15 at 23:58
  • @vikky.rk Yes but copies of the smart pointer mean that the pointer-to-element remain valid; unlike copies of the `std::function`. So a bit easier to deal with. – Yakk - Adam Nevraumont Nov 05 '15 at 00:41
  • Makes sense. One more question: Where is the lambda stored when it get converted to function pointer? – vikky.rk Nov 05 '15 at 19:14
  • @vikky.rk It isn't. There is no state to store. Well, the 1 byte no-state could be stored somewhere while it is a function, but neither calling the lambda nor the function *use* that state in any real sense. – Yakk - Adam Nevraumont Nov 05 '15 at 19:14
1

With:

class CallBack
{
public:
    explicit CallBack(std::function<void(int)> f) : f(f) {}

    static void to_c_api(int a, void* that)
    {
        reinterpret_cast<CallBack*>(that)->f(a);
    }
private:
    std::function<void(int)> f;
};

You may then do

CallBack callback; // should live longer than the calls
void register_callback(CallBack::to_c_api, &callback);
Jarod42
  • 203,559
  • 14
  • 181
  • 302