void set_ (const void *data, void (*cb)(EV_P_ ev_watcher *w, int revents)) throw ()
{
  this->data = (void *)data;
  ev_set_cb (static_cast<ev_watcher *>(this), cb);
}
// function callback
template<void (*function)(watcher &w, int)>
void set (void *data = 0) throw ()
{
  set_ (data, function_thunk<function>);
}
template<void (*function)(watcher &w, int)>
static void function_thunk (EV_P_ ev_watcher *w, int revents)
{
  function
    (*static_cast<watcher *>(w), revents);
}
Hi,
I'm using libev's C++ wrapper ev++.h. There is this piece of code in ev++.h that I know how to use as an API, but don't fully understand. I can set up a Ctrl-C watcher in the event loop as follows:
ev::sig signal_watcher(evloop); 
signal_watcher.set<sigint_cb>(); 
signal_watcher.start(SIGINT); 
where sigint_cb's function signature is :
void sigint_cb(ev::sig &w, int revents)
Can someone explain why function_thunk can magically cast my sigint_cb function signature to
void (*cb)(EV_P_ ev_watcher *w, int revents)
What C++ sorcery is this? Thanks.
function_thunk doesn't magically cast sigint_cb signature to void (*cb)(EV_P_ ev_watcher *w, int revents) it just call sigint_cb with properly casted arguments.
From the beginning, function_thunk is a function template which can be intstantiated with function pointer of type void (*)(watcher &w, int).
So basically when you will write function_thunk<sigint_cb> somewhere in your code, compiler will create corresponding function_thunk instance which will be looking like this:
void function_thunk (EV_P_ ev_watcher *w, int revents)
{
    sigint_cb(*static_cast<watcher *>(w), revents);
}
Also note that in you example ev::sig and watcher are the same types, otherwise template argument deduction/substitution for function_thunk would failed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With