Очень короткая беседа в чате привела к этому простому решению:
// is_member_function_pointer
template<typename T> struct is_member_function_pointer : public false_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...)> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) volatile> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const volatile> : public true_type {};
Включая также специализации для volatile
.
РЕДАКТИРОВАТЬ , как отметили @Xeo и @Johannes, я пропустил квалификатор ref (он же rvalue для * this) версии:
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) volatile &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const volatile &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) volatile &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const volatile &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...)> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) volatile> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const volatile> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) volatile &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const volatile &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) volatile &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const volatile &&> : public true_type {};
Что все еще вполне выполнимо. Это яснее, чем сумасшедшая магия шаблонов и множество вспомогательных шаблонов IMHO.
EDIT2 , чтобы уточнить, все вышеперечисленное находится в пространстве имен реализации и обернуто вокруг
template<typename T> constexpr bool
is_member_function_pointer() { return __implementation::is_member_function_pointer<remove_cv<T>>::result; }
Где remove_cv
- это псевдоним шаблона для удобного
template<typenamen T> using
remove_cv = typename __implementation::remove_cv<T>::type;
Полагаю, есть и другие, а может и лучшие способы, но этот, по крайней мере, понятен читателю без каких-либо дополнительных трюков SFINAE, таких как применяемые в libc ++ или libstdc ++, IMHO.