Created
April 15, 2017 20:07
-
-
Save smoofra/b614282790bca5bed36364e1219ce3e3 to your computer and use it in GitHub Desktop.
delegates: c++ function pointer + context object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <utility> | |
#include <functional> | |
#include <stdio.h> | |
template<class S> class delegate; | |
template<class Ret, class ... Args> | |
class delegate<Ret(Args...)> { | |
public: | |
typedef Ret (*invoker_t) (void *, Args && ...); | |
private: | |
invoker_t invoker; | |
void *context; | |
public: | |
static Ret invoke_fpointer(void *vf, Args && ...args) { | |
typedef Ret (*f_t) (Args...); | |
f_t f = (f_t) vf; | |
return f(std::forward<Args>(args)...); | |
} | |
template<class C, Ret (C::*Method) (Args...)> | |
static Ret invoke_method(void *vinst, Args && ...args) { | |
C *inst = (C*) vinst; | |
return (inst->*Method)(std::forward<Args>(args)...); | |
} | |
template<class C> | |
static Ret invoke_fobj(void *vobj, Args && ...args) { | |
C *obj = (C*) vobj; | |
return (*obj)(std::forward<Args>(args)...); | |
} | |
static Ret invoke_block(void *vblock, Args && ...args) { | |
typedef Ret (^block_t) (Args...); | |
block_t block = (block_t) vblock; | |
return block(std::forward<Args>(args)...); | |
} | |
public: | |
delegate() { | |
invoker = NULL; | |
context = NULL; | |
} | |
delegate(invoker_t i, void *c) { | |
invoker = i; | |
context = c; | |
} | |
delegate(const delegate &x) { | |
invoker = x.invoker; | |
context = x.context; | |
} | |
delegate(Ret (*f) (Args...)) { | |
invoker = invoke_fpointer; | |
context = (void*) f; | |
} | |
delegate(Ret (^block) (Args...)) { | |
invoker = invoke_block; | |
context = (void*) block; | |
} | |
template<class C> | |
delegate(C *f) | |
{ | |
invoker = invoke_fobj<C>; | |
context = (void*) f; | |
} | |
template<class C, Ret (C::*Method) (Args...)> | |
static delegate from_method(C* inst) { | |
return delegate(invoke_method<C, Method>, (void*)inst); | |
} | |
inline Ret operator() (Args && ...args) { | |
return invoker(context, std::forward<Args>(args)...); | |
} | |
template<class C> | |
delegate for_instance(C* inst) { | |
return delegate(invoker, (void*)inst); | |
} | |
}; | |
template<class C, class D> class delegate_factory; | |
template<class C, class Ret, class ...Args> | |
class delegate_factory<C, delegate<Ret(Args...)>> { | |
public: | |
typedef Ret (*invoker_t) (void *, Args && ...); | |
//typedef typename delegate<Ret(Args...)>::invoker_t invoker_t; | |
private: | |
invoker_t invoker; | |
public: | |
constexpr delegate_factory(invoker_t i) : invoker(i) {} | |
constexpr delegate_factory(const delegate_factory &x) : invoker(x.invoker) {} | |
constexpr static delegate_factory make(invoker_t i) { | |
return delegate_factory(i); | |
} | |
delegate<Ret(Args...)> for_instance (C *inst) { | |
return delegate<Ret(Args...)> (invoker, inst); | |
} | |
}; | |
// template<class C, class Ret, class ... Args> | |
// constexpr delegate_factory<C, delegate<Ret(Args)...>> delegate_for_method (Ret (C::*Member) (Args...)) { | |
// return delegate_factory<C, delegate<Ret(Args)...>>( &(delegate<Ret(Args)...>::template invoke_method<C, Member>) ); | |
// } | |
// template<class C, class Ret, class ... Args> | |
// constexpr delegate<Ret(Args)...> delegate_for_method (Ret (C::*Member) (Args...)) { | |
// typedef delegate<Ret(Args)...> d; | |
// return d::template from_method<C, Member>(NULL); | |
// } | |
// template<class C, class Ret, class ... Args> | |
// constexpr delegate_factory<C, delegate<Ret(Args)...>> delegate_for_method (Ret (C::*Member) (Args...)) { | |
// //return delegate_factory<C, delegate<Ret(Args)...>>::make( &(delegate<Ret(Args)...>::template invoke_method<C, Member>) ); | |
// return delegate_factory<C, delegate<Ret(Args)...>>::make( delegate<Ret(Args)...>::template invoke_method<C, Member> ); | |
// } | |
template<class C, class Ret, class ... Args> | |
constexpr delegate<Ret(Args)...> (*delegate_for_method) (C *inst) (Ret (C::*Member) (Args...)) { | |
typedef delegate<Ret(Args)...> d; | |
return d::template from_method<C, Member>; | |
} | |
void simple(int i) { | |
printf("simple %d\n", i); | |
} | |
void invoker(void *x, int &&i) { | |
printf("invoker %p %d \n", x, i); | |
} | |
class C { | |
public: | |
void method(int i) { | |
printf("method %p %d\n", this, i); | |
} | |
}; | |
int main() { | |
delegate<void(int)> d(invoker, NULL); | |
d(10); | |
auto f = [](int i) {printf ("lambda %d\n", i);}; | |
d = &f; | |
d(11); | |
d = simple; | |
d(12); | |
C inst; | |
//d = decltype(d)::from_method<C, &C::method>(&inst); | |
d = delegate_factory<C, delegate<void(int)>>( delegate<void(int)>::template invoke_method<C, &C::method> ).for_instance(&inst); | |
d = delegate_for_method(&C::method).for_instance(&inst); | |
d(13); | |
d = ^(int i) { printf ("block %i\n", i); }; | |
d(14); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment