nsf gamedevЖурнал

C++0x brain damage

Автор:

Мне правда жаль будущее поколение молодых мозго***в. Решил я как-то значицо написать супер крутой коллбэк в стиле С++0x, да не сдавался до конца..

#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;
}

5 июня 2010