Basisklasse für generische Typen vorgeben



  • Man kann sone Prüfung schon basteln. Ist halt deutlich aufwendiger als ein einfaches "extends" hinzuschreiben.



  • Schau dir doch das mal an.

    class A {
    void MachWas() {};
    //...};
    
    class B :public A {//...};
    
    class C {//...};
    
    template<class T>
       where AbgeleitetVonA<T>
       class Template { //...
    }
    // bin mir nicht ganz sicher, ob where... oder class... zuerst kommen müssen...
    // ich denke mal so.
    // Ist nicht getestet, nur so als Anregung
    

    Jetzt nur noch das Concept bastelt (so oder so ähnlich):

    concept AbgeleitetVonA<class T>
    {
    void MachWas();
    }
    
    // main.cpp o.ä.
    //(...)
    
    Template<A> template1;      // geht
    Template<B> template2;      // geht
    Template<C> template3;      // geht nicht (keine Methode "void MachWas()")
    

    So, wenn du willst, kannst du das ja mal so probieren.
    Ich weiß nicht, ob das alles so richtig ist, vielleicht musst du nochmal nach "Concepts" googeln.



  • Das scheint nicht das zu sein, was er/sie/es haben wollte. Concept-Checking ist ja "nur" ein Hilfsmittel (das in beschränktem Rahmen auch mit tausend Template-Tricks in C++98 realisierbar ist). Das ist genau das, was CStoll schon ansprach.

    Mit einem solchen Template-Trick kann man aber auch die Vererbungsbeziehung erkennen:

    template <class Super, class Sub>
    struct super_sub_class
    {
    private:
        typedef char jep;
        typedef struct { char bla[2] } ne;
    
        static Sub* ein_sub ();
    
        static jep test (const Super*);
        static ne test (...);
    
    public:
        static const bool value = sizeof (test(ein_sub ())) == sizeof (jep);
    };
    

    So ähnlich war das in Modernes C++ Design (wahrscheinlich mit besserer Namensgebung ;)).

    Das, gepaart mit einem static_assert (wie der aussieht ist hoffe ich halbwegs klar) in der Klasse spuckt dir immer, wenn du eine Klasse, die nicht von Super abgeleitet oder Super selbst ist als Template-Parameter übergibts eine Fehlermeldung aus.
    Allerdings deutet das imho stark auf einen Designfehler hin! Wozu brauchst du das denn?


  • Mod

    Dafür gibt es type_traits (is_convertible, ob wirklich Vererbung vorliegt, prüfst du ja hier gar nicht) - Alexandrescus adhoc-Lösungen sind dem allemal unterlegen.



  • .filmor schrieb:

    Allerdings deutet das imho stark auf einen Designfehler hin! Wozu brauchst du das denn?

    Ich finds auch das amn das mal hintefagen sollte:

    Ein Template nutzt einen Teil J der Menge der Methoden der Schnittstelle I des aktuellen Typs T.
    Wenn T diese Schnittstelle J anbietet dann ist es eben "auch" vom Typ J - selbst wen der nur implizit durch die Anforderungen des Templates definiert ist.

    In der STL ist das Prinzip ja imo sogar formalisiert - nämlich z.B. durch die "character traits" für strings.

    Grüsse

    *this

    P.S.: Das Thema Generik vs OOP ist imo sehr interssant z.B. beim OO/Performance-"Tradeoff" den ein vector nach sich zieht. 🙂



  • camper schrieb:

    Dafür gibt es type_traits (is_convertible, ob wirklich Vererbung vorliegt, prüfst du ja hier gar nicht) - Alexandrescus adhoc-Lösungen sind dem allemal unterlegen.

    Könntest Du für mich bitte eine "adhoc"-Lösung skizzieren?
    Oder ist das sehr aufwändig?

    Grüsse

    *this



  • .filmor schrieb:

    Das scheint nicht das zu sein, was er/sie/es haben wollte. (...)

    Ich dachte, er wollte prüfen, ob der Parameter T von einer bestimmten Basisklasse abgeleitet ist?

    Das geht natürlich mit Concepts, einfach indem er prüft, ob T die Methoden der gewünschten Basisklasse enthält.
    Wenn ja, ist sie vermutlich von dieser abgeleitet (oder sie enthält zumindest die passenden Methoden, kann also mit dem Template verwendet werden).
    Ich halte das in dem Fall für die einfachste Lösung.



  • Ist schon klar, auch aus der Sicht eines C++-Programmierers richtig gedacht, aber das wollte er trotzdem nicht. Aus irgendeinem Grund möchte er nicht nur, dass die Schnittstelle (also die Funktionen) da sind, sondern auch, dass die Klasse tatsächlich, nicht nur vermutlich, von einer bestimmten anderen abgeleitet ist. Und das lässt sich mit Concepts (zumindest meines Wissens) nicht bewerkstelligen, es wäre auch unnötig.



  • Sinthoras schrieb:

    Ich dachte, er wollte prüfen, ob der Parameter T von einer bestimmten Basisklasse abgeleitet ist?

    Ja, so verstehe ich das auch.

    Das geht natürlich mit Concepts, einfach indem er prüft, ob T die Methoden der gewünschten Basisklasse enthält.

    Und das ist natürlich Unsinn. Bloß weil die Methoden vorliegen liegt noch längst keine Vererbung vor.

    Auf Vererbung prüfen kann man, indem man prüft ob man einen Zeiger vom Typ B für nen Zeiger von Typ A einsetzen kann. Das geht zur Compilezeit. Boost hat doch auch diese metaprogramming-lib. Die bietet sicher ein derives<A,B> an. 🙂



  • Jester schrieb:

    Und das ist natürlich Unsinn. Bloß weil die Methoden vorliegen liegt noch längst keine Vererbung vor.

    Nein, natürlich nicht.
    Aber vielleicht hättest du mal weiterlesen sollen:

    (...)oder sie enthält zumindest die passenden Methoden, kann also mit dem Template verwendet werden(...)

    Ich hatte das Gefühl, darum ging es ihm.
    Für mich klingt es jedenfalls so:

    marluwie schrieb:

    (...)Wenn ich mit dem generischen Typ in der Template-Klasse arbeite, kann ich sicherstellen, dass die Methoden der Klasse Base vorhanden sind.(...)

    Und genau DAS kann man mit Concepts prüfen.

    .filmor schrieb:

    Aus irgendeinem Grund möchte er nicht nur, dass die Schnittstelle (also die Funktionen) da sind, sondern auch, dass die Klasse tatsächlich, nicht nur vermutlich, von einer bestimmten anderen abgeleitet ist.

    Ok, wenn das der Fall ist, nützen ihm Concepts natürlich wenig.
    Allerdings kann ich keinen Grund dafür sehen, dass man Datentypen mit einer passenden Schnittstelle aussschließt?!?

    Vielleicht kann er sich ja mal dazu äußern.


Anmelden zum Antworten