templatestruktur erzwingen?



  • gibt es eine saubere möglichkeit bei templates zu erzwingen, dass die templateklasse bestimmte eigenschaften mitbringt bzw eine bestimmte basisklasse hat?

    also zum beispiel, dass wenn ich ein template array habe

    template <class t>
    class my_array
    {
    //hier wird auf funktionalität von my_base zugegriffen
    //und t soll als basisklasse my_base haben, kann aber durchaus noch mehr mitbringen
    };
    

    das dann die templateklasse t als basisklasse

    class my_base
    {
    //verschiedne funktionalitäten
    };
    

    hat um sicherzustellen, dass ich auf die elemente in dem array bestimmte funktionalitäten anwenden kann.

    ich weiß, dass ich einfach davon ausgehen kann, dass die funktionalität zur verfügung steht, und dann ein fehler kommt, falls dem nicht so ist. allerdings finde ich diese variante nicht sehr gut und wollte wissen ob man das irgendwie erzwingen kann. ich hoffe es ist verständlich worauf ich hinaus will, vielen dank schon mal im voraus.



  • Wenn du dich auf deine Klassenhierarchie verlassen willst, solltest du die Templates vergessen und mit my_base-Zeigern oder Referenzen arbeiten (Stichwort: Polymorphie).

    Ansonsten geh einfach davon aus, daß der Template-Parameter alle benötigten Funktionen mitbringt - der Compiler wird sich schon beschweren, wenn er etwas nicht findet (ja ich weiß, solche Meldungen enden mitunter in langen "instantiated from here"-Listen). Damit bist du letzten Endes flexibler.



  • Hallo habe mal das hier gefunden. Vielleicht kann mir das jemand erklären. Oder funktioniert das nur Zufällig obzw. undefiniert?
    Hab schon mal soviel Kommentare wie mir möglich war eingefügt.

    template <class Derived, class Base> //Parameter sind klar
    class Check
    {
    class Nope {}; // eine leere Klasse
    class Yep {char Dummy[3];}; // eine leere Klasse mit sizeof (Yep) == 3
    static Yep Test(Base*); // ????
    static Nope Test(...); // ????
    public:
    enum {
    IsDerived = sizeof(Test(static_cast<Derived*>(0))) // ????
    == sizeof(Yep)
    };
    };
    class X {};
    class Y : public X {};
    
    int main()
    {
    cout << Check<Y, X>::IsDerived << endl;
    
    cout << Check<int, string>::IsDerived << endl;
    return 0;
    }
    


  • template <class Derived, class Base> //Parameter sind klar
    class Check
    {
    class Nope {}; // eine leere Klasse
    class Yep {char Dummy[3];}; // eine leere Klasse mit sizeof (Yep) == 3
    static Yep Test(Base*); // Test übernimmt alle Objekte vom Typ Base oder die vom Typ Base abgeleitet sind, Rückgabewert ist Yep
    static Nope Test(...); // Übernimmt den ganzen Rest, Rückgabewert = Nope
    public:
    enum {
    IsDerived = sizeof(Test(static_cast<Derived*>(0))) 
    == sizeof(Yep) // Testet ob die Größe des Rückgabewerts von Test gleich der der Klasse Yep ist. (
    Sollte egtl keine 0 gecastet werden sondern ein Objekt vom Typ Derived nach Typ Base)
    };
    };
    class X {};
    class Y : public X {};
    
    int main()
    {
    cout << Check<Y, X>::IsDerived << endl;
    
    cout << Check<int, string>::IsDerived << endl;
    return 0;
    }
    

    Diese Idee wurde u.A. in "Mondern C++ Design" Vorgestellt:

    template< typename T, typename U >
    struct conversion
    {
    	typedef char small;
    	struct big { char dummy[ 2 ]; };
    	static big test( ... );
    	static small test( U );
    	static T make_t();
    
    	enum { exists = sizeof( small ) == sizeof( test( make_t() ) ) };
    };
    
    class foo
    {};
    
    class bar : public foo
    {};
    
    int main()
    {
    	std::cout << conversion< bar, foo >::exists;
    }
    


  • also das mit dieser strukur conversion versteh ich nicht so richtig. das mit der polymorphie kann ich ja mal versuchen.



  • muss ich bei der polymorphie einfach jedes templateargument, also die templateklasse t, durch my_base ersetzen?
    also statt

    template <class t>
    class my_array
    {
      t data;
    //...
    }
    

    jetzt

    class my_array
    {
      my_base data;
    //...
    }
    

    oder wie??? wenn ich jetzt aber eine von my_base abgeleitete klasse habe und die 'data' zuweise dann bleibt doch nur noch das zeugs aus my_base übrig, oder? also die abgeleitete klasse wird doch dann quasi auf my_base heruntergeschraubt.



  • Wieso nicht einfach implizit auf by_base* konvertieren?

    class my_base
    {
    public:
        virtual void foo(int i) = 0;
        // ...
    };
    
    template <class T> class bar
    {
    public:
        void baz(T* t)
        {
            my_base* mb = t; // hier krachts (natürlich beim compilieren schon!) beim
                             // spezialisieren wenn die konvertierung nicht möglich/erlaubt ist
            mb->foo(123);
        }
    };
    

    Oder aber man verwendet "duck typing" und verlangt nicht dass von my_base geerbt wird, sondern bloss dass die Funktion "foo" (mit einer passenden Signatur) vorhanden ist. Was eigentlich die üblichere weil meist sinnvollere Variante ist:

    template <class T> class bar
    {
    public:
        void baz(T* t)
        {
            t->foo(123);
        }
    };
    

    EDIT: *PEINLICH* ... hatte die Funktion im Template "bar" auch "bar" genannt, was natürlich nicht geht *pfeiff*. Hab's korrigiert. *pfeiff*



  • nagut wenn das die übliche weise ist, dann werde ich das auch so machen.



  • Hi,

    es entspricht eben der klassischen C++-Strategie: Nur das festlegen, was man wirklich braucht !
    Und das ist hier eben die Schnittstelle (=benötigte Member) - ob sie die von irgendwo geerbt haben, ist da eigentlich nicht wichtig.

    Gruß,

    Simon2.


Anmelden zum Antworten