#include template struct extract_type { using type = typename extract_type::type; }; template struct extract_type<0, T, Ts...> { using type = T; }; template struct callable_info_base { using return_type = Ret; template using parameter_type = typename extract_type::type; static constexpr std::size_t parameter_count { sizeof...(Args) }; }; template struct callable_info_helper {}; // #1: extract information from a function template struct callable_info_helper : public callable_info_base {}; // #2: extract information from a function pointer template struct callable_info_helper : public callable_info_base {}; // #3: extract info from a non-const member function template struct callable_info_helper : public callable_info_base {}; // #4: extract info from a const member function template struct callable_info_helper : public callable_info_base {}; template callable_info_helper get_callable_info(int); template callable_info_helper get_callable_info(float); template using callable_info = decltype(get_callable_info(0)); /*** testcases ***/ void fun(int, float); struct X { int operator()(X&); }; struct Y { Y& operator()(char, float) const; }; int main() { using function_t = callable_info; static_assert( std::is_same_v< function_t::return_type, void > ); static_assert( std::is_same_v< function_t::parameter_type<0>, int > ); static_assert( std::is_same_v< function_t::parameter_type<1>, float > ); static_assert( function_t::parameter_count == 2 ); using functor_t = callable_info; static_assert( std::is_same_v< functor_t::return_type, int > ); static_assert( std::is_same_v< functor_t::parameter_type<0>, X& > ); static_assert( functor_t::parameter_count == 1 ); using const_functor_t = callable_info; static_assert( std::is_same_v< const_functor_t::return_type, Y& > ); static_assert( std::is_same_v< const_functor_t::parameter_type<0>, char > ); static_assert( std::is_same_v< const_functor_t::parameter_type<1>, float > ); static_assert( const_functor_t::parameter_count == 2 ); auto lambda = [](int, int, int) { return 0; }; using lambda_t = callable_info< decltype( lambda ) >; static_assert( std::is_same_v< lambda_t::return_type, int > ); static_assert( std::is_same_v< lambda_t::parameter_type<0>, int > ); static_assert( std::is_same_v< lambda_t::parameter_type<1>, int > ); static_assert( std::is_same_v< lambda_t::parameter_type<2>, int > ); static_assert( lambda_t::parameter_count == 3 ); }