?

Log in

No account? Create an account
 

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

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

Previous Entry Ugly C++ technique that I'm still proud of thinking of Sep. 4th, 2009 @ 11:21 pm

This is x-posted from an entry in my journal.

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.

This should work even if you have the global variable in question inside an anonymous namespace.

Current Mood: pleasedpleased
Leave a comment
[User Picture Icon]
From:ataxi
Date:September 5th, 2009 03:15 pm (UTC)
(Link)
Interesting. Just to check, when you use a static class member function like that to represent a C-flavoured callback, there aren't any problems with calling convention? Library callbacks are usually 'cdecl' and I can remember having some problems in that area with cross-language interop with higher level stuff - but I haven't read up on it recently.
[User Picture Icon]
From:omnifarious
Date:September 5th, 2009 03:25 pm (UTC)
(Link)

That might very well be. I don't have access to a platform in which that's an issue. In my opinion if a compiler is supporting different calling conventions the calling convention should be part of the type of a function. If things are done that way the code should cause the compiler to give you an error.

[User Picture Icon]
From:lertulo
Date:September 5th, 2009 11:58 pm (UTC)
(Link)
Twisted, but an interesting approach. Thanks for the tip; I hope I never have to use it.

BTW: my game-based avatar is cooler than your game-based avatar. 8-)
[User Picture Icon]
From:omnifarious
Date:September 6th, 2009 03:11 am (UTC)
(Link)

I don't think anybody has proved chess to be turing complete. In fact, I'm pretty sure it isn't. *big grin*

(Deleted comment)
[User Picture Icon]
From:omnifarious
Date:September 7th, 2009 12:48 am (UTC)
(Link)

What if you need 5 or 10 instances of your callback within a single thread? Do you write a special function for each one?

(Leave a comment)
Top of Page Powered by LiveJournal.com