2016-05-05 7 views
1

Ich möchte eine Vorlage-Klasse mit Spezialisierung von einigen Methoden für verschiedene Typen definieren.Verwenden Sie Vorlage mit Basisklasse als Parameter

template <typename T> 
class Handler { 
public: 
    void method1() { method2(); } 
protected: 
    void method2(); 
} 

dann in der Implementierungsdatei:

template <> Handler<int>::method2() { doSomething(); } 
template <> Handler<float>::method2() { doSomethingElse(); } 
template <> Handler<ClassB>::method2() { doSomethingDifferent(); } 

Bisher funktioniert alles ok.

Nun möchte ich einige neue Klassen definieren, die von ClassB abgeleitet sind, und die Template-Spezialisierung auf Objekte dieser Klassen verwenden. Natürlich kompiliert es, verbindet aber nicht, da die Spezialisierung für jede Unterklasse fehlt.

Gibt es eine Möglichkeit, die Vorlage für diese zu verwenden, zum Beispiel mit SFINAE?

+0

Sie könnten Ihre Template-Code in Ihre Header-Datei - das ist wahrscheinlich nicht das, was du bist Suche nach, obwohl – tobspr

+0

Vorlage Spezialisierung unterscheidet sich konzeptionell von Vererbung. Sie können keine Vorlage mit einer Mitgliedsfunktion haben, die nicht definiert ist, und erwarten, dass sie so funktioniert. Suchen Sie vielleicht nach [CRTP] (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)? Wenn nicht, seien Sie bitte klarer, was Sie erreichen möchten. – jPlatte

Antwort

2

ich oft auf einem Typ-Tag eine gute alterantive Spezialisierung finden Überlastung:

namespace { 

template<class T> struct Type { using type = T; }; // Or boost::type<T> 
template<class T> struct TypeTag { using type = Type<T>; }; 

struct ClassB {}; 

template <typename T> 
class Handler { 
public: 
    void method1() { 
     method2(typename TypeTag<T>::type{}); // Call an overloaded function. 
    } 
protected: 
    void method2(Type<int>) { std::printf("%s\n", __PRETTY_FUNCTION__); } 
    void method2(Type<float>) { std::printf("%s\n", __PRETTY_FUNCTION__); } 
    void method2(Type<ClassB>) { std::printf("%s\n", __PRETTY_FUNCTION__); } 
}; 

// Somewhere else. 
struct ClassC : ClassB {}; 
template<> struct TypeTag<ClassC> { using type = Type<ClassB>; }; 

} // namespace 

int main(int ac, char**) { 
    Handler<ClassB> b; 
    b.method1(); 

    Handler<ClassC> c; 
    c.method1(); 
} 

Ausgänge:

void {anonymous}::Handler<T>::method2({anonymous}::Type<{anonymous}::ClassB>) [with T = {anonymous}::ClassB] 
void {anonymous}::Handler<T>::method2({anonymous}::Type<{anonymous}::ClassB>) [with T = {anonymous}::ClassC] 
+1

Ich werde es ausprobieren. Das sieht aus wie die klassische Lösung mit einer zusätzlichen Ebene der Indirektion. –

+0

@GB Ja, Ihre Beobachtung ist genau richtig. Eine andere Möglichkeit, es zu betrachten, besteht darin, dass Sie alle Typen mehreren bestimmten Kategorien zuordnen. 'TypeTag ' ordnet Typ 'T' der Kategorie' TypeTag :: type' zu. Durch die Spezialisierung 'TypeTag ' kann eine Kategorie für jeden Typ definiert werden. –

1

Erstens:

template <class T,class=void> 
class Handler 

dann SFINAE verwenden, um eine Spezialisierung zu erstellen:

template <class T> 
class Handler<T,std::enable_if_t<test>> 

Jetzt haben, dass die Spezialisierung entweder umfassen ihre Umsetzung in seinem Körper oder erben von einer Implementierung Typ (Nicht- Vorlage) und implementiere das in der impl-Datei.

Für Ihre Zwecke könnte der Test Basis sein.

Ihr int impl benötigt jetzt einen ,void Parameter.

Sie können auch eine Traits-Klasse verwenden, um eine bedingte Zuordnung durchzuführen.