Template :"Nur best Typen"



  • Hab noch ma Beitrag editiert ^^
    Und ja - das hatte ich ja vorhin schon bemerkt, dass es doch nur einer ist ^^

    Von daher ist das template vll wirklich ein wenig... wie soll ich sagen... fehl am platz ^^

    also hast ja recht 🤡

    bb



  • Nexus schrieb:

    @ Jihhaaaa:
    Wenn ein Template nur zwei Typen (typedefs) unterstützen soll und diese Typen dann auch noch identisch sind, ist eine normale, nicht-generische Klasse eher angebracht.

    Werde ich immer so überlesen? :p



  • weils sonst unfair mir gegenüber gewesen wäre ^^
    (ich war eher)

    unskilled schrieb:

    PS: warum verschiedene typedefs für gleiche typen? Oo

    :p :p :p



  • Aber ich war es, der als erster darauf hingewiesen hat, normale Klassen zu nehmen. :p

    Nein, jetzt mal im Ernst, warum sollte man in diesem Fall (1 zugelassener Typ) ein Template nehmen? Wie bist du auf die Idee gekommen, Jihhaaaa? 😉



  • Ich habe meinen vorletzten Beitrag nochmal erweitert (also den Beitrag vor diesem). 😃



  • Du musst also für N Typen auch N Implementierungen spezialisieren, sowie denn allgemeinen Fall verbieten.

    das müsste man bei richtigen Klassen auch - also N klassen für N typen (wobei ich nen kleines n nehmen würde xP )
    den allg Fall verbieten.. das is ja rel. schnell gemacht...
    also ich denke, es würde beim programmieren mit der klasse einfach besser aussehen - und für den compiler ist es wahrscheinlich egal, ob template oder eigene klasse...

    und wer will schon so ne klassen:

    class Taufgabe_int {};
    class Taufgabe_bool {};
    class Taufgabe_vector_const_iter_shouldnt_be_the_end_iterator_of_an_vector_or_deque_or_list_or_something_like_this {/*toll, oder : >*/};
    

    ^^

    bb



  • unskilled schrieb:

    das müsste man bei richtigen Klassen auch - also N klassen für N typen (wobei ich nen kleines n nehmen würde xP )

    Darum geht es doch. Wenn man eh nur N Fälle zulassen will, und die Menge N überschaubar bleibt, nimmt man besser Klassen anstatt Klassen-Templates. Man kann zweiteres natürlich schon nehmen, aber das ist irgendwie Schwachsinn.



  • ich würd die template-lösung (für mehr als einen typen ^^) der klassen-name-mit-variablen-typ-verunstalten-version vorziehen - selbst, wenn es mehr arbeit ist...



  • Tachyon schrieb:

    Darum geht es doch. Wenn man eh nur N Fälle zulassen will, und die Menge N überschaubar bleibt, nimmt man besser Klassen anstatt Klassen-Templates. Man kann zweiteres natürlich schon nehmen, aber das ist irgendwie Schwachsinn.

    Wenn sich die Klassen aber nur im Typ unterscheiden, kann man sich eine grosse Menge Code sparen, und als Nebeneffekt erhält man noch eine bessere Übersicht und Wartbarkeit. Ausserdem muss man nicht für jede Klasse den Bezeichner kennen.

    Im Notfall kann man ja immer noch typedefs machen (was ich aber sehr unschön finde)...



  • Nexus schrieb:

    Tachyon schrieb:

    Darum geht es doch. Wenn man eh nur N Fälle zulassen will, und die Menge N überschaubar bleibt, nimmt man besser Klassen anstatt Klassen-Templates. Man kann zweiteres natürlich schon nehmen, aber das ist irgendwie Schwachsinn.

    Wenn sich die Klassen aber nur im Typ unterscheiden, kann man sich eine grosse Menge Code sparen, und als Nebeneffekt erhält man noch eine bessere Übersicht und Wartbarkeit. Ausserdem muss man nicht für jede Klasse den Bezeichner kennen.

    Im Notfall kann man ja immer noch typedefs machen (was ich aber sehr unschön finde)...

    Nein, kann man eben nicht. Man kann nicht spezialisieren, ohne dass man für jede Spezialisierung eine Implementierung liefert.
    Entweder, man macht ein allgemeines Template, und lebt damit, dass jeder Typ erlaubt ist, oder man implementiert N mal spezialisiert. So oder so.
    Die beste Möglichkeit ist, denke ich, die von mir oben genannte PIMPL-Idiom-Variante.



  • Du hast natürlich Recht das der Zusammenhang nicht einwandfrei ist, ich wollte eigentlich nur auf dein
    "Wie willst Du das durch Spezialisierung hinbekommen? Insbesondere den Teil, dass ein Template für die nichtspezialisierten Fälle nicht definiert ist?
    Spezialisierung ist nicht dafür da, die Benutzbarkeit eines Templates einzuschränken." eingehen.

    Mini-Conatiner Beispiel. Mal versuchen...

    template<class T> class MiniContainerImpl {
    public:
         MiniContainerImpl() {...};
         ~MiniContainerImpl() {...};
    
         void add(T value) {...};
         void remove(T value) {...};
         T get(int index) {...}
    private:
         T *values;
    };
    
    template<class T> class MiniContainer;
    template<> class MiniContainer<double> : public MiniContainerImpl<double> { };
    template<> class MiniContainer<MyType> : public MiniConatinerImpl<MyTye>  { };
    

    Weiss net ob das so funktioniert. Habs net getestet, auch programmier ich schon länger nicht mehr in C++. Doch aus meiner logischen Sicht spricht nichts dagegen ausser diverse Kleinigkeiten die ich nimma genau weiss, wie Beispielweise das virtual vor dem Destruktor von der Basisklasse. Doch hab ich noch düster in Erinnerung, das es nicht empfehlenswert ist bei Templates.

    Klar kann man jetzt auch noch MiniContainerImpl direkt benützten, was ich finde immer noch nicht das ware ist. Aber was besseres ist mir auf die Schnelle nicht eigefallen.

    Hab auch nichts dagegen wenn du mich eines bessern belehrst 😉

    Gruß
    Baracke

    PS: Wie darf ich mir das PIMPL vorstellen, einen Pointer auf ne Forward deklartion im Classheader? Kannste mir vielleicht einen guten Link geben, könnte vielleicht ab und an nützlich sein.



  • Ne, geht nicht. Du benutzt Deine Impl nicht für nur zwei Typen, sondern machst Deine Impl für genau zwei Typen zu nichte. 😉



  • Tachyon schrieb:

    [...]

    Stimmt, da habe ich mir wohl zu wenig dabei überlegt.

    Mit normalen Klassen gibt es ja auch noch die Möglichkeit zur Vererbung. Oder eben die typedef -Variante, bei der man dann aber wieder das Template für alle Typen nutzen könnte, und die daher nicht wirklich sinnvoll ist. Das Template müsste eben nicht in seiner Grundform anwendbar sein (also versteckt oder so) 😉



  • Aber die Lösung find ich toll

    @tachyon: versteh deinen Einwand nicht...

    template <class T>
    	class test_
    		{ 
    			private: 
    				 T value; 
    			protected: 
    				 test_ (const T &a) {value = a;};
    			public:
    				 T get () {return value;}; 
    		}; 
    
    template <class T>
    	class test;
    
    template < >
    	class test <char>	: public test_ <char>
    		{
    			public:
    				test (char a) : test_ (a) {};
    		};
    
    int main ()
    	{
    		test <char> eins ('A');
    		char A = eins.get ();
    	}
    

    geht doch einwandfrei...

    bb



  • Die Lösung ist für den Fall nur suboptimal, da die Implementierung für den "Benutzer" noch frei zugänglich ist und somit zu Fehlern verleitet. Ne Doku kann das natrülich kompensieren. Trozdem nicht das gelbe vom Ei, zumal der Threadersteller im Prinzip nur einen Typ verwendet.

    Ja die Impl wird immer allgemein bleiben müssen, zumindestens eine soweit ich weiss. Der Clou wäre halt die Implementierung nicht zugänglich zu machen ausser von den Klassen, was man zwar mit privat and friend bewerkstelligen könnte. Doch müsste man jedesmal die Basisklasse anfassen wenn man noch einen Typ hinzufügen möchte. Kann gewünscht sein oder auch nicht.

    Wie auch immer, wenn du eine bessere Lösung für einen Container der nur endlich viele Typen akzeptiert hast nur her damit.

    Gruß
    Baracke



  • Baracke_out schrieb:

    PS: Wie darf ich mir das PIMPL vorstellen, einen Pointer auf ne Forward deklartion im Classheader? Kannste mir vielleicht einen guten Link geben, könnte vielleicht ab und an nützlich sein.

    Das Beispiel ist einfach, und nicht gerade sinnig, aber es zeigt die grundlegende Funktion:

    template_pimpl_demo.hpp

    //template fwd. decl.
    template<class T> struct Implemention;
    
    //demo struct
    struct MyData{};
    
    //Float dekl.
    class FloatClass
    {
    public:
        FloatClass();
        ~FloatClass();
        void putData(float a);
        float getData() const;
    private:
        std::auto_ptr<Implemention<float> > myImpl;
    };
    
    //MyData dekl.
    class MyDataClass
    {
    public:
        MyDataClass();
        ~MyDataClass();
        void putData(const MyData& a);
        MyData getData() const;
    private:
        std::auto_ptr<Implemention<MyData> > myImpl;
    };
    

    template_pimpl_demo.cpp

    #include "template_pimpl_demo.hpp"
    
    //Impl. def., für alle Impl.
    template<class T> struct Implemention
    {
        void putData(T a)
        {
            theData = a;
        }
        T getData() const
        {
            return theData;
        }
    
        T theData;
    };
    
    ////////////////////////////////////////
    //FloatClass uses impl.
    FloatClass::FloatClass()
    :myImpl(new Implemention<float>())
    { }
    
    FloatClass::~FloatClass()
    { }
    
    void FloatClass::putData(float a)
    {
        myImpl->putData(a);
    }
    
    float FloatClass::getData() const
    {
        return myImpl->getData();
    }
    
    ////////////////////////////////////////
    //MyDataClass uses impl.
    MyDataClass::MyDataClass()
    :myImpl(new Implemention<MyData>())
    { }
    
    MyDataClass::~MyDataClass()
    { }
    
    void MyDataClass::putData(const MyData& a)
    {
        myImpl->putData(a);
    }
    
    MyData MyDataClass::getData() const
    {
        return myImpl->getData();
    }
    

    Btw. optimiert das auch noch die Compilezeit. 😉



  • Tschuldige hab jetzt grad keine Zeit mehr mir das genauer anzuschauen, da ich um 16 Uhr einen Artztermin hab. Aber wenn ich das richtig verstehe kann man dadurch das Interface von der Implementierung komplett trennen was zur Folge hat das die Compileabhängikeiten sinken? Mal davon abgesehen das die Implemenierung nicht direkt zugänglich ist?

    Gruß
    Baracke



  • Baracke_out schrieb:

    Tschuldige hab jetzt grad keine Zeit mehr mir das genauer anzuschauen, da ich um 16 Uhr einen Artztermin hab. Aber wenn ich das richtig verstehe kann man dadurch das Interface von der Implementierung komplett trennen was zur Folge hat das die Compileabhängikeiten sinken? Mal davon abgesehen das die Implemenierung nicht direkt zugänglich ist?

    Gruß
    Baracke

    Das ist der Sinn. Geht auch wunderbar bei Nicht-Template-Klassen.

    PS: Die gute Implemention soll natürlich Implementation heissen. :p



  • Baracke_out schrieb:

    Der Clou wäre halt die Implementierung nicht zugänglich zu machen ausser von den Klassen

    Hab ich doch mit nem protected gemacht...
    wenn man von ner Klasse ableitet, dann wird man schon wissen, was man macht... Halte private / friend da für völlig übertrieben...

    bb



  • unskilled schrieb:

    Aber die Lösung find ich toll[...]

    Ich finde sie ziemlich hässlich... 😉


Anmelden zum Antworten