2012-05-17 6 views
6

Ich weiß, dass das in C++ 03 nicht möglich war, aber ich hoffe, dass es einen neuen Voodoo gibt, der mir erlaubt, dies zu tun. Siehe unten:Gibt es in C++ 11 sowieso, um Mitglied Zeigertyp innerhalb einer Vorlage zu erhalten?

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

Gibt es eine Möglichkeit, dies in C++ 11 zu tun? Will declltype Hilfe?

** UPDATE: Verwenden von Vlads Beispiel war ich so etwas wie dieses Denken funktionieren würde (Einschränkung: Ich habe nicht kompiliert, wie ich den Compiler mit decltype Unterstützung jetzt bin Gebäude)

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

würde diese Arbeit?

+2

Da Sie es explizit angeben, bezweifle ich, dass es einen Weg gibt. Es sollte sogar in C++ 03 funktionieren, wenn es stattdessen 'AddMatch (& TestType :: i)' war. –

+2

Was müssen Sie mit dem Zeiger-zu-Element tun? Es kann sein, dass es eine bessere Lösung gibt, als einen Zeiger-zu-Element als Nicht-Typ-Vorlagenparameter zu verwenden. – bames53

Antwort

3

Was Sie zu tun versuchen, kann nicht ausgeführt werden, dh Sie können einen Mitgliedszeiger nicht als konstanten Ausdruck verwenden, es sei denn, Sie haben einen Typ. Das heißt, der Typ eines Nicht-Typ-Vorlagenarguments muss angegeben werden, oder anders ausgedrückt, es gibt keine Typrückschlüsse für Vorlagenargumente.

+0

Eigentlich denke ich, Vlad ist auf dem richtigen Weg. Ich werde mit seinem Konzept ein bisschen spielen und sehen, ob es zu meinem was passt ... – Jaime

+0

@Jaime: Bist du sicher? In Vlads Code ist das Argument für die Vorlage nur der * Typ * der Member-Funktion, aber die Member-Funktion wird nicht als Template-Argument übergeben. Wenn Sie den Pointer-to-Member als Kompilierzeitkonstante haben wollen, müssen Sie ihn wie folgt aufrufen: 'b.AddMatch ();', was ist noch mühsamer, wenn man es nicht hinter einem Makro versteckt (was mir als Idee nicht ganz gefällt). Wenn es Ihnen nichts ausmacht, den pointer-to-member als einen Laufzeitwert zu haben, dann können Sie ihn an die Funktion übergeben und der Compiler wird sie ableiten, aber das ändert das Problem. –

+0

...was kballo im Kommentar zu deiner Frage aufgezeigt hat. –

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

Ja, das würde funktionieren Ich wette, aber ich möchte verhindern, dass meine Benutzer decltype angeben müssen. Ich schätze, ich könnte FT dazu zwingen, ein Mitgliedsfeld mit Merkmalen zu sein und einen konstanten Parameter zu erstellen, der declltype (& TestType: i) ... – Jaime

+0

Das funktioniert nicht. Der Vorlagenparameter aus der Frage ist ein nicht typisierter Vorlagenparameter. Die Funktion AddMatch wird für einen Zeiger auf Member und nicht auf den Typ eines Zeigers für Member parametrisiert. – bames53

+0

Das löst das ursprüngliche Problem nicht, es ersetzt nur das erste Argument 'int' durch einen schwerfälligen' decltype (& TestType :: i) '(und vergisst dabei, den eigentlichen Zeiger auf member als zweites Template-Argument anzugeben ...) Wo im ursprünglichen Code 'TestType :: i' ein bekannter Wert ist, verschwindet in dieser Antwort der tatsächliche Wert (nur der Typ ist dort) –

2

Wie dies über (als Kicker es in c arbeitet ++ 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

Das ist es, was die beiden Kommentare vorschlagen: das Template-Argument als Funktionsargument zu ändern. Es ist in Ordnung, wenn Sie nicht möchten/wollen, dass der Zeiger auf ein Member ein Template-Argument ist ... –

+0

Ah, ja, das stimmt. Ich sehe keine Vorteile der Schnittstelle, die das Poster verwenden möchte, verglichen damit, es einfach als Argument für die Typableitung zu übergeben. – Ylisar

+0

Nun, der generierte Code könnte im Falle eines Template-Arguments etwas schneller sein, da der Compiler den exakten Aufruf injizieren kann, anstatt über den Zeiger zu senden, aber wie Sie sagen, wird es in den meisten Szenarien keinen Unterschied machen. +1 –

2

Sie könnten "T" machen diese Informationen zur Verfügung stellen.

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

Dann wird es einfach

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

Alternativ können Sie verwenden Freund Funktionsdefinitionen

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

Dann können Sie schreiben

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); 
} 
Verwandte Themen