Vererbung mit Klassentemplate, Templateparameter in Initialisierungsliste



  • Moin moin,

    ich habe eine Basisklasse, die recht viele Templateparameter hat. Von dieser leite ich ab und setzte dabei für alle Templateparameter feste Typen ein. Also die abgeleitete Klasse ist kein Template mehr.

    Beispiel:

    template <typename T, typename U, typename V, typename W>
    struct A {
    	A(std::string s) 
    	{ };
    
    	T i;
    	U j;
    	V k;
    	W l;
    };
    
    struct B : public A<int, long, float, double> {
    	B(int i) :
    		A<int, long, float, double>( "Hallo" )
    	{};
    };
    

    Kompilieren tut dies auch :-).
    Was ich unschön finde ist, dass ich die Templateparameter beim Aufrufen des Konstructors der Basisklasse erneut angeben muss.

    Lasse ich die Parameter weg, beschwert sich der Kompiler, dass es keinen Defaultkonstruktor in A gibt und als nächster Fehler, dass A kein Member von B ist.

    Das macht auch Sinn, nur gibt es vielleicht eine Möglichkeit, den Konstruktoraufruf eleganter zu gestallten? Zum einen ist diese Variante nicht gerade leserlich, zum anderen muss man immer an zwei Stellen im Code was arbeiten, wenn der Typ sich ändert.

    cu
    Thundernail



  • typedef A<int,long,float,double> A_t;
    
    struct B : A_t {
        B(int i) :
            A_t("Hallo" )
        {};
    };
    


  • Das blöde ist, dass typedef nur bei Typen, deren Template-Parameter alle feststehen, funktioniert.

    Wenn du also so etwas hast:

    template <typename T, typename U>
    struct A
    {
    };
    
    template <typename T>
    struct B : public A<T, int>
    {
    };
    

    Musst du das Typedef innerhalb der Definition von B schreiben und hast dadurch mindestens einmal Codeduplizierung (wenn du keine Makros verwendest).



  • @drakon: Rekordverdächtige Antwortgeschwindigkeit 😉
    Von so einem fliegenden Typedef bin ich zwar nicht begeistert, aber es erfüllt erstmal alle wichtigen Anforderungen.
    Danke.

    @Nexus: Mein B ist selbst kein Template (zumindestenz bis jetzt nicht... *hoff*) aber danke für den Hinweis. Vielleicht ist das wirklich mal eine Ausnahmestelle für ein Makro.

    Thundernail



  • Thundernail schrieb:

    Von so einem fliegenden Typedef bin ich zwar nicht begeistert, aber es erfüllt erstmal alle wichtigen Anforderungen.
    Danke.

    Warum nicht?
    Das wird sogar oft so gemacht, wenn man ein Klassentemplate hat und dann ein paar gängige Typen definieren will. (macht die Standardbibliothek recht oft, z.B alleine schon std::string ).

    Normalerweise ist das typedef dann einfach im Header, wo das Template steht, aber ansonsten ist das sehr gängig.



  • drakon schrieb:

    Das wird sogar oft so gemacht, wenn man ein Klassentemplate hat und dann ein paar gängige Typen definieren will. (macht die Standardbibliothek recht oft, z.B alleine schon std::string ).

    Normalerweise ist das typedef dann einfach im Header, wo das Template steht, aber ansonsten ist das sehr gängig.

    Nur weil es eine gängige Lösung ist, muss ich ja nicht begeistert sein ;). Aber scheint die _beste_ Lösung in C++ zu sein.

    Mich stört z.B. der Pseudoname, denn ich da vergeben muss.

    typedef A<int> A_B;
    struct B : A_B {
        B(int i) :
            A_B("Hallo" )
        {};
    };
    
    typedef A<unsigned int> A_C;
    struct C : A_C {
        C(int i) :
            A_C("Hallo" )
        {};
    };
    
    typedef A<long> A_D;
    struct D : A_D {
        D(int i) :
            A_D("Hallo" )
        {};
    };
    

    Gute Nacht.



  • Hmm... Was wäre denn deiner Ansicht nach eine schöne Lösung? Beim Konstruktor nur noch den Klassennamen ohne Parameter angeben zu müssen? An anderen Orten liesse sich das ja trotzdem nicht vermeiden...

    Ebenfalls gute Nacht. 🙂



  • Du könntest den typedef auch in die Basisklasse packen:

    template <typename T, typename U, typename V, typename W>
    struct A {
        typedef typename A<T,U,V,W> A_base;
        A(std::string s) 
        { };
    
        T i;
        U j;
        V k;
        W l;
    };
    
    struct B : public A<int, long, float, double> {
        B(int i) :
            A_base( "Hallo" )
        {};
    };
    

    Im Zweifel kannst du den typedef noch protected machen, dann ist sichergestellt dass er wirklich nur von erbende Klassen verwendet wird.


Log in to reply