Journal of Omnifarious - Ugly C++ technique that I'm still proud of thinking of

Sep. 4th, 2009

11:21 pm - Ugly C++ technique that I'm still proud of thinking of

Previous Entry Share Next Entry

I'm quite pleased with myself. :-) I've been participating on stackoverflow.com recently. HazyBlueDot had an interesting question in which (s)he was trying to use ::boost::function to get around a broken library interface.

In particular, the library interface allowed you to register a callback function, but it did not provide you a way of giving it a void * or something to pass back to you so you could put its call of your function back in context. HazyBlueDot was trying to use boost::function in combination with boost::bind to add in the pointer and then call his own function. The only problem is that the result boost::function object then couldn't produce an ordinary function pointer to pass to the callback.

This, of course, cannot be done in a static language like C++. It requires on the fly generation of first-class functions. C++ simply can't do that. But, there are various interesting tricks you can pull to generate functions at compile time with templates in ways that can help with this problem, even if they can fully solve it.

I'm particularly pleased with my solution, which looked something like this:

#include <boost/function.hpp>

using ::boost::function;

typedef int (*callback_t)(const char *, int);

typedef function<int(const char *, int)> MyFTWFunction;

template <MyFTWFunction *callback>
class callback_binder {
 public:
   static int callbackThunk(const char *s, int i) {
      return (*callback)(s, i);
   }
};

extern void register_callback(callback_t f);

int random_func(const char *s, int i)
{
   if (s && *s) {
      return i;
   } else {
      return -1;
   }
}

MyFTWFunction myfunc;

int main(int argc, const char *argv[])
{
   myfunc = random_func;
   register_callback(&callback_binder<&myfunc>::callbackThunk);
   return 0;
}

This basically allows you to automatically generate a 'thunk' function, a normal non-member function that can be passed to the callback, that then calls another function and adds the contents of a global variable you specify as a template parameter. It doesn't fully solve the problem, but it partially solves it. And I think in this case it will do something pretty close to what HazyBlueDot wants.

Tags: , ,
Current Location: 2237 NW 62nd ST, 98107
Current Mood: [mood icon] pleased
Current Music: Aimee Mann - One
(Leave a comment)