Skip to content

Instantly share code, notes, and snippets.

@Matthewacon
Created April 5, 2020 23:30
Show Gist options
  • Save Matthewacon/42a1297121757741f6c3a1546ebf6f86 to your computer and use it in GitHub Desktop.
Save Matthewacon/42a1297121757741f6c3a1546ebf6f86 to your computer and use it in GitHub Desktop.
#include <cstdio>
#include <stdlib.h>
//Stub environment
struct Environment {
int GetRegister(int i) const {
printf("GetRegister(%d)\n", i);
return i;
}
};
//Actual implementation
template<auto F, typename = decltype(F)>
struct Invoker;
//Forward to Invoker<F, R (*)(Args...)>
template<auto F, typename R, typename... Args>
struct Invoker<F, R (*)(Args...) noexcept> {
[[gnu::always_inline]]
inline static R invoke(const Environment& env) {
return Invoker<F, R (*)(Args...)>::invoke(env);
}
};
template<auto F, size_t N, typename...>
struct InternalInvoker;
template<auto F>
struct InternalInvoker<F, 0> {
template<typename R, typename... Values>
[[gnu::always_inline]]
inline static R internal_invoke(const Environment& env, Values... values) {
return (*F)(values...);
}
};
template<auto F, size_t N, typename T, typename... TS>
struct InternalInvoker<F, N, T, TS...> {
template<typename R, typename... Values>
[[gnu::always_inline]]
inline static R internal_invoke(const Environment& env, Values... values) {
return InternalInvoker<F, N - 1, TS...>::template internal_invoke<R, T, Values...>(env, static_cast<T>(env.GetRegister(N - 1)), values...);
}
};
template<auto F, typename R, typename... Args>
struct Invoker<F, R (*)(Args...)> {
static_assert(sizeof...(Args) < 8);
//TODO add static_assert for Args to ensure that conversion from int to Arg is valid
//static_assert((CX::IsCastable<Args, int>::value && ...));
[[gnu::always_inline]]
inline static R invoke(const Environment& env) {
return InternalInvoker<F, sizeof...(Args), Args...>::template internal_invoke<R>(env);
}
};
void test(int i1, float i2, short i3) {
printf("test: %d %f %hi\n", i1, i2, i3);
}
double test2(double d, long l) noexcept {
printf("test2: %f %ld\n", d, l);
return d + l;
}
int main() {
Environment env;
Invoker<test>::invoke(env);
auto ret = Invoker<test2>::invoke(env);
printf("test2 returned %f\n", ret);
auto ptr = Invoker<malloc>::invoke(env);
if (ptr) {
free(ptr);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment