Наконец-то нашли способ сделать это в C ++ 03, используя частичную специализацию. Необходимы многочисленные перегрузки для различного числа аргументов и константных / volatile функций, но идея заключается в следующем:
/* An empty template struct, this gets chosen if the given template parameter is not a member function */
template <typename _Func>
struct MemberFunctionInfo { };
/* Specialization for parameterless functions */
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 };
};
/* Specialization for parameterless const functions */
template <typename _Result, typename _Class>
struct MemberFunctionInfo<_Result (_Class::*) () const> : MemberFunctionInfo<_Result (_Class::*) ()> { };
/* Specialization for functions with one parameter */
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 };
};
/* Specialization for const functions with one parameter */
template <typename _Result, typename _Class, typename P0>
struct MemberFunctionInfo<_Result (_Class::*) (P0) const> : MemberFunctionInfo<_Result (_Class::*) (P0)> { };
.
.
.
Пример использования:
template <typename MemFunc>
int getArity(MemFunc fn) {
// Can also use MemberFunctionInfo<MemFunc>::parameter_types with boost::mpl
return MemberFunctionInfo<MemFunc>::arity;
}
Приведенное выше решение имеет некоторые недостатки. Он не обрабатывает ссылки на функции, функции, не являющиеся членами или volatile
/ const volatile
функций-членов, но их легко учесть, добавив больше специализаций.
Для C ++ 11 подход, упомянутый @Useless, намного чище и должен быть предпочтительным.