реализация is_member_function_pointer - PullRequest
2 голосов
/ 22 января 2012

Я пытаюсь реализовать свой собственный is_member_function_pointer, и у меня возникают проблемы с ним.

namespace __implementation
{
    // integral_constant
    template<typename T, T v>
    struct integral_constant
    {
        static constexpr T result = v;
        typedef integral_constant<T,v> type;
        constexpr operator T() { return result; }
    };
    // true_type
    typedef integral_constant<bool, true> true_type;
    // false_type
    typedef integral_constant<bool, false> false_type;
    // remove_const
    template<typename T> struct remove_const { typedef T type; };
    template<typename T> struct remove_const<const T> { typedef T type; };
    // remove_volatile
    template<typename T> struct remove_volatile { typedef T type; };
    template<typename T> struct remove_volatile<volatile T> { typedef T type; };
    // remove_cv
    template<typename T> struct remove_cv
    { typedef typename remove_volatile<typename remove_const<T>::type>::type type; };
    // is_function - ugliness ahead due to variadic functions!
    template<typename T, typename... Args> struct is_function : public false_type {};
    template<typename T, typename... Args> struct is_function<T(Args...)> : public true_type {}; // normal function
    template<typename T, typename... Args> struct is_function<T(Args......)> : public true_type {}; // variadic function
    // is_member_function_pointer
    template<typename T> struct is_member_function_pointer : public false_type {};
    template<typename T, typename Class> struct is_member_function_pointer<T Class::*> : public is_function<T> {};   
}
/*
 * Short forms: either alias templates or constexpr functions
 */
// remove_const
template<typename T>
using remove_const = typename __implementation::remove_const<T>::type;
// remove_volatile
template<typename T>
using remove_volatile = typename __implementation::remove_volatile<T>::type;
// remove_cv
template<typename T>
using remove_cv = typename __implementation::remove_cv<T>::type;
// is_member_function_pointer
template<typename T>
constexpr bool is_member_function_pointer { return __implementation::is_member_function_pointer<T>::result; }
// is_function
template<typename T>
constexpr bool is_function() { return __implementation::is_function<typename __implementation::remove_cv<T>::type>::result; }

Проблема заключается в обычных указателях функций, которые не работают, как они должны для шаблона member_function_pointer,Кроме того, указатели на константные функции-члены не распознаются как member_function_pointer, что весьма печально.Как я могу исправить эту реализацию?Я полагаю, что могу enable_if специализировать указатель на обычную функцию, чтобы обойти проблему с указателем на обычную функцию, но я не вижу выхода из проблемы с указателем на функцию-член const (я буквально пытался добавлять remove_cv и const везде вопределение типа черты, безрезультатно).Я вижу, что текущий is_member_function_pointer не обрабатывает функцию-член класса const, но я не знаю, какую синтаксическую магию я могу использовать для этого.

Любая помощь приветствуется.

Ответы [ 2 ]

4 голосов
/ 22 января 2012

Очень короткая беседа в чате привела к этому простому решению:

// 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.

2 голосов
/ 25 января 2012

С другой стороны

template<typename T> struct remove_c { typedef T type; };
template<typename T> struct remove_c<T const> { typedef T type; };

template<bool C> 
struct bool_ { static bool const value = C; };

template<typename T, typename U>
struct is_same : bool_<false> {};

template<typename T>
struct is_same<T, T> : bool_<true> { };

template<typename T, typename = bool_<true> >
struct is_function : bool_<false> {};

struct C { };

template<typename T>
struct is_function< T, 
   bool_<is_same<typename remove_c<T>::type const C::*, 
                 typename remove_c<T>::type       C::*>::value> > 
  : bool_<true> {};

template<typename T>
struct is_member_function_pointer_impl : bool_<false> {};

template<typename T, typename C>
struct is_member_function_pointer_impl<T C::* const volatile>
  : is_function<T> {};

template<typename T>
struct is_member_function_pointer 
  : is_member_function_pointer_impl<T const volatile> {};
...