Skip to content

Instantly share code, notes, and snippets.

@sasq64
Last active October 1, 2017 08:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sasq64/0d4fccaac1db9c7dc6b7 to your computer and use it in GitHub Desktop.
Save sasq64/0d4fccaac1db9c7dc6b7 to your computer and use it in GitHub Desktop.
C++ Type erased dispatch - or whatever
#include <cstdio>
#include <functional>
#include <string>
#if __cplusplus <= 201200L
namespace std {
// index_sequence
template <std::size_t...> struct index_sequence {};
template <std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
template <std::size_t... Is>
struct make_index_sequence<0u, Is...> : index_sequence<Is...> { using type = index_sequence<Is...>; };
};
#endif
// Non template, type erased base class
struct FunctionCaller {
virtual int call() = 0;
// getArg is the problem specific bits, these are just dummy implementations
template <class T> T getArg(int index, T*);
std::string getArg(int index, std::string *) {
return "yay";
}
int getArg(int index, int*) {
return index;
}
};
template<typename... X> struct FunctionCallerFunctor;
// Deal with Functors/Lambdas
template <class STATE, class FX, class RET, class... ARGS> struct FunctionCallerFunctor<STATE, FX, RET (FX::*)(ARGS...) const> : public FunctionCaller {
FunctionCallerFunctor(STATE *state, FX f) : state(state), func(f) {
}
template <size_t ... A> RET apply(std::index_sequence<A...>) {
return func(FunctionCaller::getArg(A, (ARGS*)nullptr)...);
}
int call() override {
apply(std::make_index_sequence<sizeof...(ARGS)>());
return 0;
}
FX func;
STATE *state;
};
// Deal with member functions
template <class CLASS, class RET, class... ARGS> struct FunctionCallerMember : public FunctionCaller {
FunctionCallerMember(CLASS *c, RET (CLASS::*f)(ARGS...)) : c(c), func(f) {
}
template <size_t ... A> RET apply(std::index_sequence<A...>) {
return (c->*func)(FunctionCaller::getArg(A, (ARGS*)nullptr)...);
}
int call() override {
apply(std::make_index_sequence<sizeof...(ARGS)>());
return 0;
}
RET (CLASS::*func)(ARGS...);
CLASS *c;
};
template <class FX> FunctionCaller* registerFunction(const char *name, FX f) {
return new FunctionCallerFunctor<void,FX,decltype(&FX::operator()) >(nullptr, f);
}
template <class STATE, class FX> FunctionCaller* registerFunction(STATE *state, const char *name, FX f) {
return new FunctionCallerFunctor<STATE, FX, decltype(&FX::operator()) >(state, f);
}
template <class CLASS, class RET, class... ARGS> FunctionCaller* registerFunction(const char *name, CLASS *c, RET (CLASS::*f)(ARGS...)) {
return new FunctionCallerMember<CLASS, RET, ARGS...>(c, f);
}
//
struct SomeStuff {
int someFunc(int x, int y) {
printf("Adding %d and %d\n", x, y);
return x+y;
}
};
int main() {
SomeStuff data;
FunctionCaller *fc;
fc = registerFunction(&data, "testX", [=](int, std::string t, int x) {
printf("%s %d\n", t.c_str(), x);
});
fc->call();
fc = registerFunction("test", [=](std::string t, int x) {
printf("Hello %d\n", x);
});
fc->call();
fc = registerFunction("test2", &data, &SomeStuff::someFunc);
fc->call();
return 0;
}
@sasq64
Copy link
Author

sasq64 commented Dec 7, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment