2012-05-17 3 views
6

Я знаю, что это невозможно в C++ 03, но я надеюсь, что есть несколько новых вуду, которые позволят мне это сделать. См. Ниже:Есть ли в C++ 11, чтобы получить тип указателя члена в шаблоне?

template <class T> 
struct Binder 
{ 
    template<typename FT, FT T::*PtrTomember> 
    void AddMatch(); 
}; 
struct TestType 
{ 
    int i; 
}; 
int main(int argc, char** argv) 
{ 
    Binder<TestType> b; 
    b.AddMatch<int,&TestType::i>(); //I have to do this now 
    b.AddMatch<&TestType::i>(); //I'd like to be able to do this (i.e. infer field type) 
} 

Есть ли способ сделать это в C++ 11? Помогло ли decltype?

** UPDATE: Используя пример Влада я думал что-то вроде этого будет работать (предостережение: я не скомпилированы как я строю компилятор с поддержкой decltype сейчас)

template <class T> 
struct Binder 
{ 
    template<typename MP, FT ft = decltype(MP)> 
    void AddMatch() 
    { 
     //static_assert to make sure MP is a member pointer of T 
    } 
}; 
struct TestType 
{ 
    int i; 
}; 
int main() 
{ 
    Binder<TestType> b; 
    b.AddMatch<&TestType::i>(); 
} 

Будет ли это работать?

+2

Учитывая, что вы явно указываете это, я сомневаюсь, что есть способ. Он должен работать даже в C++ 03, если вместо этого был «AddMatch (& TestType :: i)». –

+2

Что вам нужно сделать с указателем на член? Может быть, есть лучшее решение, чем использование указателя-к-члену в качестве параметра шаблона непигового типа. – bames53

ответ

3

То, что вы пытаетесь сделать, не может быть сделано, то есть, вы не можете использовать указатель члена в качестве постоянного выражения, если у вас есть тип. Таким образом, должен быть указан тип аргумента шаблона, отличного от типа, или, другими словами, для аргументов шаблона нет вывода типа.

+0

На самом деле я думаю, что Влад на правильном пути. Я немного поиграю с его концепцией и посмотрю, подходит ли мне то, что я делаю ... – Jaime

+0

@ Jaime: Вы уверены? В коде Влада аргумент шаблона - это только * тип * функции-члена, но функция-член не передается в качестве аргумента шаблона. Если вы хотите, чтобы указатель-член был константой времени компиляции, вам нужно вызвать его так: 'b.AddMatch ();', что еще более громоздким, если вы не спрячете его за макросом (который мне не совсем нравится как идея). Если вы не возражаете, если указатель-к-член как значение времени выполнения, то вы можете передать его функции, и компилятор выведет его, но это изменит проблему. –

+0

...о чем, по словам Кальбо, в комментарии к вашему вопросу. –

0
template <class T> 
struct Binder 
{ 
    template<typename FT> 
    void AddMatch(); 
}; 

struct TestType 
{ 
    int i; 
}; 

int main() 
{ 
    Binder<TestType> b; 
    b.AddMatch<decltype(&TestType::i)>(); 
} 
+0

Да, это сработает, но я бы хотел, чтобы мои пользователи не указали decltype. Я предполагаю, что могу заставить FT быть полем-членом с чертами и создать постоянный параметр, который захватывает decltype (& TestType: i) ... – Jaime

+0

Это не работает. Параметр шаблона из вопроса является несимметричным параметром шаблона. Функция AddMatch параметризуется указателем на элемент, а не типом указателя на член. – bames53

+0

Это не решает исходную проблему, она просто заменяет первый аргумент 'int' более громоздким' decltype (& TestType :: i) '(и забывает предоставить фактический указатель на член как второй аргумент шаблона ...) Где в исходном коде 'TestType :: i' известное значение, в этом ответе фактическое значение исчезает (только тип есть) –

2

Как об этом (как кикер он работает в C++ 03):

#include <iostream> 
#include <typeinfo> 

template< typename T > struct ExtractMemberTypeHelper; 
template< typename R, typename T > 
struct ExtractMemberTypeHelper< R(T::*) > 
{ 
    typedef R Type; 
    typedef T ParentType; 
}; 

template< typename T > 
struct ExtractMemberType : public ExtractMemberTypeHelper<T> {}; 

struct foo 
{ 
    int bar; 
    template< typename T > 
    void func(const T& a_Arg) 
    { 
     std::cout << typeid(typename ExtractMemberType<T>::Type).name() << " " << typeid(typename ExtractMemberType<T>::ParentType).name() << std::endl; 
    } 
}; 

int main() 
{ 
    foo inst; 
    inst.func(&foo::bar); 
} 
+0

Вот что предлагают два комментария: изменение аргумента шаблона в качестве аргумента функции. Это нормально, если вам не нужно/нужно, чтобы указатель на член был аргументом шаблона ... –

+0

Ах, да, это правда. Я не совсем понимаю преимущества интерфейса, который плакат хочет использовать, но по сравнению с просто передачей его в качестве аргумента для вывода типа. – Ylisar

+0

Ну, сгенерированный код может быть немного быстрее в случае аргумента шаблона, поскольку компилятор может вводить точный вызов, а не отправлять его через указатель, но, как вы говорите, в большинстве сценариев это не изменит ситуацию. +1 –

2

Вы могли бы сделать "T" предоставить эту информацию.

template <class ...T> 
struct BoundTypes { }; 

template <class U, class T> 
struct BinderDecls { 
    void AddMatch(); 
}; 

template <class U, class T, class ...Ts> 
struct BinderDecls<U, BoundTypes<T, Ts...>> 
    :BinderDecls<U, BoundTypes<Ts...>> 
{ 
    using BinderDecls<U, BoundTypes<Ts...>>::AddMatch; 

    template<T U::*PtrTomember> 
    void AddMatch(); 
}; 

template <class T> 
struct Binder : BinderDecls<T, typename T::bound_types> 
{ } 

Тогда становится легко

struct TestType { 
    typedef BoundTypes<int, float> bound_types; 

    int i; 
    float j; 
}; 

int main(int argc, char** argv) 
{ 
    Binder<TestType> b; 
    b.AddMatch<&TestType::i>(); 
    b.AddMatch<&TestType::j>(); 
} 

В качестве альтернативы вы можете использовать определения друг функции

template <class ...T> 
struct BoundTypes { }; 

template <class U, class T> 
struct BinderDecls { 
    template<T U::*ptr> 
    friend void addMatch(BinderDecl &u) { 
    // ... 
    } 
}; 

template <class U, class ...Ts> 
struct BinderDecls<U, BoundTypes<Ts...>> : BinderDecls<U, Ts>... 
{ }; 

template<typename = void> 
void addMatch() = delete; 

template <class T> 
struct Binder : BinderDecls<T, typename T::bound_types> 
{ } 

Тогда вы можете написать

struct TestType { 
    typedef BoundTypes<int, float> bound_types; 

    int i; 
    float j; 
}; 

int main(int argc, char** argv) 
{ 
    Binder<TestType> b; 
    addMatch<&TestType::i>(b); 
    addMatch<&TestType::j>(b); 
}