Skip to content

Instantly share code, notes, and snippets.

@adityaruplaha
Created February 21, 2021 14:02
Show Gist options
  • Save adityaruplaha/bd200527b4d420f17e8c96c8c498c88b to your computer and use it in GitHub Desktop.
Save adityaruplaha/bd200527b4d420f17e8c96c8c498c88b to your computer and use it in GitHub Desktop.
Function Reflection
#include <tuple>
#include <type_traits>
namespace Common {
template <typename... Ts>
class TypeSeq;
template <>
class TypeSeq<> {
public:
constexpr static unsigned int length = 0;
constexpr static bool has = false;
constexpr static bool is = false;
template <typename... Us>
constexpr static bool is_eq(const TypeSeq<Us...> = {}) {
return false;
}
template <typename U>
constexpr static bool is_eq(const TypeObject<U> = {}) {
return false;
}
};
template <typename T>
class TypeObject {
using self = Common::TypeObject<T>;
public:
template <typename U>
constexpr static bool has = (std::is_same_v<T, U>);
template <typename U, typename... Un>
constexpr static bool is = (TypeSeq<Un...>::length == 0 ? self::has<U> : false);
template <typename... Us>
constexpr static bool is_eq(const TypeSeq<Us...> = {}) {
return self::is<Us...>;
}
template <typename U>
constexpr static bool is_eq(const TypeObject<U> = {}) {
return self::is<U>;
}
};
template <typename T>
class TypeSeq<T> {
using self = Common::TypeSeq<T>;
public:
template <unsigned N, std::enable_if_t<N == 0, bool> = true>
using member = T;
constexpr static unsigned int length = 1;
template <typename U>
constexpr static bool has = (std::is_same_v<T, U>);
template <typename U, typename... Un>
constexpr static bool is = (TypeSeq<Un...>::length == 0 ? self::has<U> : false);
template <typename... Us>
constexpr static bool is_eq(const TypeSeq<Us...> = {}) {
return self::is<Us...>;
}
template <typename U>
constexpr static bool is_eq(const TypeObject<U> = {}) {
return self::is<U>;
}
};
template <typename T0, typename... Tn>
class TypeSeq<T0, Tn...> {
using self = Common::TypeSeq<T0, Tn...>;
public:
constexpr static unsigned int length = 1 + TypeSeq<Tn...>::length;
template <unsigned N, std::enable_if_t<(self::length > N), bool> = true>
using member = decltype(std::get<N>(std::declval<std::tuple<T0, Tn...>>()));
template <typename U>
constexpr static bool has = (std::is_same_v<T0, U> || TypeSeq<Tn...>::template has<U>);
template <typename U0, typename... Un>
constexpr static bool is = self::length == TypeSeq<U0, Un...>::length &&
std::is_same_v<T0, U0> && (TypeSeq<Tn...>::template is<Un...>);
template <typename... Us>
constexpr static bool is_eq(const TypeSeq<Us...> = {}) {
return self::is<Us...>;
}
template <typename U>
constexpr static bool is_eq(const TypeObject<U> = {}) {
return false;
}
};
} // namespace Common
#include <functional>
#include "common.hpp"
namespace FunctionReflection {
template <typename R, typename... Args>
class FunctionReflector {
public:
explicit constexpr FunctionReflector(R (*)(Args...)) {}
explicit constexpr FunctionReflector(std::function <R (Args...)>) {}
// No function reflection on C-style variadic functions.
explicit constexpr FunctionReflector(R (*)(Args..., ...)) = delete;
explicit constexpr FunctionReflector(std::function <R (Args..., ...)>) = delete;
using return_type = R;
template <unsigned N>
using argument = typename Common::TypeSeq<Args...>::member<N>;
constexpr static unsigned int arg_count = Common::TypeSeq<Args...>::length;
};
} // namespace FunctionReflection
#include <cstdio>
#include "fn_reflect.hpp"
bool efn(int, int, float, long);
bool vfn(char, int, float, double, ...);
int main() {
constexpr auto t0 = decltype(FunctionReflection::FunctionReflector(&efn))::arg_count;
// Not allowed.
// constexpr auto t0 = decltype(FunctionReflection::FunctionReflector(&vfn))::arg_count;
constexpr auto t1 = decltype(FunctionReflection::FunctionReflector(&efn))::argument<3>{};
constexpr bool s0 = Common::TypeSeq<int, int, float, float, long>::has<float>;
using s1_p0 = Common::TypeSeq<int, int, float, float, long>;
using s1_p1 = Common::TypeSeq<int, int, float, float, long>;
constexpr bool s1 = (s1_p0::is_eq(s1_p1{}));
printf("t0: %d\n", t0);
printf("t1: %s\n", typeid(t1).name());
printf("s0: %s\n", s0 ? "true" : "false");
printf("s1: %s\n", s1 ? "true" : "false");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment