#pragma once #include <cstdlib> #include <functional> #include <tuple> namespace ss { //////////////// // function traits //////////////// template <size_t N, typename T, typename... Ts> struct decayed_arg_n { static_assert(N - 1 != sizeof...(Ts), "index out of range"); using type = typename decayed_arg_n<N - 1, Ts...>::type; }; template <typename T, typename... Ts> struct decayed_arg_n<0, T, Ts...> { using type = std::decay_t<T>; }; template <typename T> struct function_traits; template <typename R, typename C, typename Arg> struct function_traits<std::function<R(C&, const Arg&) const>> { using arg_type = Arg; }; template <typename R, typename... Ts> struct function_traits<R(Ts...)> { using arg0 = typename decayed_arg_n<0, Ts...>::type; }; template <typename R, typename... Ts> struct function_traits<R(Ts...) const> : function_traits<R(Ts...)> {}; template <typename R, typename... Ts> struct function_traits<R(Ts...)&> : function_traits<R(Ts...)> {}; template <typename R, typename... Ts> struct function_traits<R(Ts...) const&> : function_traits<R(Ts...)> {}; template <typename R, typename... Ts> struct function_traits<R(Ts...) &&> : function_traits<R(Ts...)> {}; template <typename R, typename... Ts> struct function_traits<R(Ts...) const&&> : function_traits<R(Ts...)> {}; template <typename MemberFunction> struct member_wrapper; template <typename R, typename T> struct member_wrapper<R T::*> { using arg_type = typename function_traits<R>::arg0; }; //////////////// // has method //////////////// #define INIT_HAS_METHOD(method) \ template <typename T> \ class has_m_##method { \ template <typename C> \ static std::true_type test(decltype(&C::method)); \ \ template <typename C> \ static std::false_type test(...); \ \ public: \ constexpr static bool value = decltype(test<T>(0))::value; \ }; \ \ template <typename T> \ constexpr bool has_m_##method##_t = has_m_##method<T>::value; } /* trait */