5 Sep 2009 Omnifarious   » (Journeyer)

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

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.

Syndicated 2009-09-05 06:21:45 from Lover of Ideas

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!