Skip to content

Instantly share code, notes, and snippets.

@nsf
Created August 8, 2010 21:12
Show Gist options
  • Select an option

  • Save nsf/514544 to your computer and use it in GitHub Desktop.

Select an option

Save nsf/514544 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <functional>
//-------------------------------------------------------------------------
// Our main callback class, can be binded to function or member function
// of a particular class easily(?)
//-------------------------------------------------------------------------
template <typename Ret, typename ...Args>
struct funcptr_def {
typedef Ret (*type)(Args...);
};
template <typename Signature>
struct callback;
template <typename Ret, typename ...Args>
struct callback<Ret(Args...)> {
typedef typename funcptr_def<Ret, Args..., void*>::type function_ptr_type;
function_ptr_type fptr;
void *data;
void bind(function_ptr_type fptr, void *data = 0)
{
this->fptr = fptr;
this->data = data;
}
Ret call(Args ...args)
{
return (*fptr)(std::forward<Args>(args)..., data);
}
};
//-------------------------------------------------------------------------
// Helper binder
//-------------------------------------------------------------------------
template <int ...> struct int_tuple {};
template <int I, typename IntTuple, typename ...Types>
struct make_indices_impl;
template <int I, int ...Indices, typename T, typename ...Types>
struct make_indices_impl<I, int_tuple<Indices...>, T, Types...>
{
typedef typename make_indices_impl<I+1, int_tuple<Indices..., I>, Types...>::type type;
};
template <int I, int ...Indices>
struct make_indices_impl<I, int_tuple<Indices...>> {
typedef int_tuple<Indices...> type;
};
template <typename ...Types>
struct make_indices : make_indices_impl<0, int_tuple<>, Types...> {};
//-------------------------------------------------------------------------
template <typename T>
void *get_void_ptr(T &&arg)
{
return arg;
}
template <typename T, typename ...Args>
void *get_void_ptr(T &&arg, Args &&...args)
{
return get_void_ptr(std::forward<Args>(args)...);
}
//-------------------------------------------------------------------------
template <typename Ret>
struct callback_helper_impl {
template <typename T, typename MemberFunctionPtr, typename ...Args, int ...Indices>
static Ret callback_run(T *object, MemberFunctionPtr m, const std::tuple<Args&...>& args, int_tuple<Indices...>)
{
return (object->*m)(std::get<Indices>(args)...);
}
};
template <typename Signature, typename MemberSignature, MemberSignature FunctionPtr>
struct callback_helper;
template <typename Ret, typename ...Args, typename T, typename ...MemArgs, Ret(T::*MemberFunction)(MemArgs...)>
struct callback_helper<Ret(Args...), decltype(MemberFunction), MemberFunction> {
typedef typename make_indices<MemArgs...>::type indices;
static Ret function(Args ...args)
{
T *object = (T*)get_void_ptr(args...);
return callback_helper_impl<Ret>::callback_run(object, MemberFunction, std::tie(args...), indices());
}
};
// for convenience (orly?!!?111 omgwtfbbq)
#define WRAP_METHOD(f) decltype(f), f
//-------------------------------------------------------------------------
// Example class
//-------------------------------------------------------------------------
struct dog_t {
void bark(int a, int b)
{
printf("bark! %d %d\n", a, b);
}
};
//-------------------------------------------------------------------------
// Example function
//-------------------------------------------------------------------------
void say_hello(int a, int b, void *notused)
{
printf("Hello! %d %d\n", a, b);
}
int main(int argc, char **argv)
{
dog_t dog;
callback<void (int, int)> cb;
int i = 1;
// function
cb.bind(say_hello);
cb.call(i, 2);
// member function
cb.bind(callback_helper<void (int, int, void*), WRAP_METHOD(&dog_t::bark)>::function, &dog);
cb.call(i, 2);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment