2012-05-17 10 views
6

Wiem, że nie było to możliwe w C++ 03, ale mam nadzieję, że pojawi się jakiś nowy voodoo, który pozwoli mi to zrobić. Zobacz poniżej:Czy jest jeszcze w C++ 11, aby uzyskać typ wskaźnika członka w szablonie?

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) 
} 

Czy jest jakiś sposób, aby to zrobić w C++ 11? Czy pomoże Ci typ decltype?

** UPDATE: Korzystanie przykład Vlada Myślałam coś jak to będzie działać (uwaga: nie mam skompilowane jako buduję kompilator z decltype wsparciu teraz)

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>(); 
} 

to będzie działać?

+2

Biorąc pod uwagę, że wyraźnie określasz to, wątpię, czy jest jakiś sposób. Powinien działać nawet w C++ 03, jeśli zamiast tego był "AddMatch (& TestType :: i)". –

+2

Co należy zrobić ze wskaźnikiem na członka? Możliwe, że istnieje lepsze rozwiązanie niż użycie wskaźnika do elementu jako nieopisanego parametru szablonu. – bames53

Odpowiedz

3

To, co próbujesz zrobić, nie może zostać wykonane, to znaczy, nie możesz użyć wskaźnika członka jako wyrażenia stałego, chyba że masz typ. Oznacza to, że należy podać typ argumentu szablonu innego niż typ lub innymi słowy, nie ma wnioskowania o typie dla argumentów szablonu.

+0

W rzeczywistości myślę, że Vlad jest na dobrej drodze. Będę grał z jego koncepcją i zobacz, czy pasuje to do tego, co robię ... – Jaime

+0

@Jaime: Jesteś pewien? W kodzie Vlada, argumentem do szablonu jest tylko * typ * funkcji składowej, ale funkcja składowa nie jest przekazywana jako argument szablonu. Jeśli chcesz mieć wskaźnik do członka jako stałą czasu kompilacji, musisz wywołać ją w następujący sposób: 'b.AddMatch ();', który jest jeszcze bardziej nieporęczne, chyba że ukryjesz je za makro (co nie podoba mi się jako pomysł). Jeśli nie masz nic przeciwko posiadaniu wskaźnika do elementu jako wartości środowiska wykonawczego, możesz przekazać go do funkcji, a kompilator je wyprowadzi, ale to zmieni problem. –

+0

...to właśnie wskazał Kballo w komentarzu do twojego pytania. –

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

Tak, to by działało Założę się, ale chciałbym uniemożliwić moim użytkownikom określenie typu decltype. Sądzę, że mógłbym zmusić FT do zostania członkiem pola z cechami i stworzyć stały parametr, który chwyta decltype (& TestType: i) ... – Jaime

+0

To nie działa. Parametr szablonu z pytania jest parametrem szablonu non-type. Funkcja AddMatch jest parametryzowana na wskaźniku do elementu, a nie na typie wskaźnika do elementu. – bames53

+0

To nie rozwiązuje pierwotnego problemu, po prostu zastępuje pierwszy argument 'int' bardziej uciążliwym' decltype (& TestType :: i) '(i zapomina podać rzeczywisty wskaźnik do elementu jako drugi argument szablonu ...) Gdzie w oryginalnym kodzie "TestType :: i" jest znaną wartością, w tej odpowiedzi wartość rzeczywista znika (tylko typ jest tam) –

2

Jak o tym (jako kicker to działa w 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

Oto, co sugerują dwie komentarze: zmiana argumentu szablonu na argument funkcji. Jest w porządku, jeśli nie potrzebujesz/chcesz, aby wskaźnik do elementu był argumentem szablonu ... –

+0

Ah, tak, to prawda. Nie widzę jednak żadnych zalet interfejsu, którego plakat chce użyć, w przeciwieństwie do podania go jako argumentu do odliczenia typu. – Ylisar

+0

Generowany kod może być nieco szybszy w przypadku argumentu szablonu, ponieważ kompilator może wprowadzić dokładne wywołanie, zamiast przesyłać je przez wskaźnik, ale jak pan twierdzi, w większości scenariuszy nie robi to różnicy. +1 –

2

można zrobić "T" dostarczania tych informacji.

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> 
{ } 

Wtedy staje się łatwe

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>(); 
} 

Alternatywnie można użyć przyjaciel funkcja definicje

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> 
{ } 

Następnie można napisać

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); 
} 
Powiązane problemy