Garciat
1/1/2015 - 9:59 PM

function_traits.cpp

struct meow {
	void f(int, char, float) { }
};

template <typename FType>
void test() {
	using FTypeTraits = function_traits<FType>;
	
	static_assert(typename FTypeTraits::arity() == 3, "fail");

	static_assert(std::is_same<typename FTypeTraits::result_type, void>(), "fail");
	static_assert(std::is_same<typename FTypeTraits::template arg_type<0>, int>(), "fail");
	static_assert(std::is_same<typename FTypeTraits::template arg_type<1>, char>(), "fail");
	static_assert(std::is_same<typename FTypeTraits::template arg_type<2>, float>(), "fail");
}

void test1() {
	using FType = void(int, char, float);
	
	test<FType>();
}

void test2() {
	using FType = function_type<decltype(&meow::f)>::type;
	
	test<FType>();
}

void test3() {
	using FType = function_type<void(* const volatile &)(int, char, float)>::type;
	
	test<FType>();
}

void test4() {
	using FType = function_type<std::function<void(int, char, float)>>::type;
	
	test<FType>();
}
#include <type_traits>
#include <tuple>
#include <functional>

template <typename FType>
struct function_traits;

template <typename RType, typename... ArgTypes>
struct function_traits<RType(ArgTypes...)> {
	using arity = std::integral_constant<size_t, sizeof...(ArgTypes)>;
	
	using result_type = RType;
	
	using arg_tuple = std::tuple<ArgTypes...>;
	
	template <size_t Index>
	using arg_type = typename std::tuple_element<Index, arg_tuple>::type;
};

namespace details {
	template <typename T>
	struct function_type_impl
	  : function_type_impl<decltype(&T::operator())>
	{ };
	
	template <typename RType, typename... ArgTypes>
	struct function_type_impl<RType(ArgTypes...)> {
		using type = RType(ArgTypes...);
	};
	
	template <typename RType, typename... ArgTypes>
	struct function_type_impl<RType(*)(ArgTypes...)> {
		using type = RType(ArgTypes...);
	};
	
	template <typename RType, typename... ArgTypes>
	struct function_type_impl<std::function<RType(ArgTypes...)>> {
		using type = RType(ArgTypes...);
	};
	
	template <typename T, typename RType, typename... ArgTypes>
	struct function_type_impl<RType(T::*)(ArgTypes...)> {
		using type = RType(ArgTypes...);
	};
	
	template <typename T, typename RType, typename... ArgTypes>
	struct function_type_impl<RType(T::*)(ArgTypes...) const> {
		using type = RType(ArgTypes...);
	};
}

template <typename T>
struct function_type
	: details::function_type_impl<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
{ };

// --- shortcuts ---

template <typename FType>
using function_type_traits_t = function_traits<typename function_type<FType>::type>;

template <typename FType>
constexpr auto function_arity_val = function_type_traits_t<FType>::arity::value;

template <typename FType>
using function_arg_tuple_t = typename function_type_traits_t<FType>::arg_tuple;