Finally found a way to do this in C ++ 03 using partial specialization. Many overloads are needed for a different number of arguments and constant / unstable functions, but the idea is as follows:
template <typename _Func> struct MemberFunctionInfo { }; template <typename _Result, typename _Class> struct MemberFunctionInfo<_Result (_Class::*) ()> { typedef _Class class_type; typedef _Result result_type; typedef boost::tuple<> parameter_types; enum { arity = 0 }; }; template <typename _Result, typename _Class> struct MemberFunctionInfo<_Result (_Class::*) () const> : MemberFunctionInfo<_Result (_Class::*) ()> { }; template <typename _Result, typename _Class, typename P0> struct MemberFunctionInfo<_Result (_Class::*) (P0)> { typedef _Class class_type; typedef _Result result_type; typedef boost::tuple<P0> parameter_types; enum { arity = 1 }; }; template <typename _Result, typename _Class, typename P0> struct MemberFunctionInfo<_Result (_Class::*) (P0) const> : MemberFunctionInfo<_Result (_Class::*) (P0)> { }; . . .
Usage example:
template <typename MemFunc> int getArity(MemFunc fn) {
The above solution has some disadvantages. It does not process references to functions, non-member functions, or volatile / const volatile member functions, but it is easy to take them into account by adding additional specializations.
For C ++ 11, the approach mentioned by @Useless is cleaner and should be preferred.
source share