# include <functional>
# include <tuple>
# include <type_traits>
# include <iostream>
using namespace std; template < typename T >
struct function_traits ;
template < typename RET , typename . . . ARGS>
struct function_traits < RET ( ARGS. . . ) >
{ constexpr static size_t arity = sizeof . . . ( ARGS) ; using function_type = RET ( ARGS. . . ) ; using Ret_type = RET; using stl_functional_type = std:: function< function_type> ; using function_pointer = RET ( * ) ( ARGS. . . ) ; template < size_t I> struct ArgN { static_assert ( I < arity, "failed!" ) ; using type = std:: tuple_element_t< I, std:: tuple< ARGS. . . >> ; } ; template < size_t I> using ArgN_t = typename ArgN < I> :: type;
} ;
template < typename RET , typename . . . ARGS>
struct function_traits < RET ( * ) ( ARGS. . . ) > : function_traits< RET ( ARGS. . . ) > { using function_type = RET ( * ) ( ARGS. . . ) ;
} ;
template < typename RET , typename . . . ARGS>
struct function_traits < std:: function< RET ( ARGS. . . ) >> : function_traits< RET ( ARGS. . . ) > { using function_type = std:: function< RET ( ARGS. . . ) > ;
} ;
# define FUNCTION_TRAITS ( . . . ) \
template < typename RET , typename Class , typename . . . ARGS> \
struct function_traits < RET ( Class:: * ) ( ARGS. . . ) __VA_ARGS__> : function_traits< RET ( ARGS. . . ) > { \ using function_type = RET ( Class:: * ) ( ARGS. . . ) __VA_ARGS__; \
protected : \ using logic_function_type= RET ( ARGS. . . ) ; \
} ; FUNCTION_TRAITS ( )
FUNCTION_TRAITS ( const )
FUNCTION_TRAITS ( volatile )
FUNCTION_TRAITS ( const volatile )
template < typename Callable >
struct function_traits : function_traits < decltype ( & Callable:: operator ( ) ) > { using function_type = typename function_traits < Callable> :: logic_function_type;
} ; template < typename T >
void Print_Type ( )
{ std:: cout << typeid ( T) . name ( ) << std:: endl;
} int Print ( int , double ) { return 0 ; }
struct MyStruct
{ double Fn ( char , char ) const { return 0 ; } char operator ( ) ( double , char * ) { return ' ' ; }
} ; int main ( )
{ auto fn = std:: function < int ( int , double ) > ( Print) ; Print_Type < function_traits< decltype ( fn) > :: function_type> ( ) ; constexpr auto nargs = function_traits< decltype ( Print) > :: arity; Print_Type < function_traits< decltype ( Print) > :: function_type> ( ) ; Print_Type < function_traits< decltype ( & Print) > :: function_type> ( ) ; Print_Type < function_traits< MyStruct> :: function_type> ( ) ; Print_Type < function_traits< decltype ( & MyStruct:: Fn) > :: function_type> ( ) ; using T = decltype ( & MyStruct:: Fn) ; Print_Type < T> ( ) ; Print_Type < function_traits< decltype ( Print) > :: Ret_type> ( ) ; Print_Type < function_traits< decltype ( Print) > :: function_pointer> ( ) ; Print_Type < function_traits< decltype ( Print) > :: ArgN_t< 1 >> ( ) ; return 0 ;
}