Skip to content

Instantly share code, notes, and snippets.

@smoofra
Created April 15, 2017 20:07
Show Gist options
  • Save smoofra/b614282790bca5bed36364e1219ce3e3 to your computer and use it in GitHub Desktop.
Save smoofra/b614282790bca5bed36364e1219ce3e3 to your computer and use it in GitHub Desktop.
delegates: c++ function pointer + context object
#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