Template :"Nur best Typen"



  • 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... 😉



  • Tachyon schrieb:

    unskilled schrieb:

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

    Ich finde sie ziemlich hässlich...

    Hab ich meinen Geschmack denn so am Arsch? 😞 ^^
    Find sie eigtl so gar schöner als deine - aber naja...

    Ich zieh mich dann ma als Verlierer aus der Diskussion zurück ^^

    bb : )



  • Jihhaaaa schrieb:

    Was muss ich tun, damit nur t_cCont und t_lCont verwendbar sind für den Typ der Templateklasse?

    typedef std::vector<std::pair<double,CStateEvent*> > t_vCont;
    typedef std::vector<std::pair<double,CStateEvent*> > t_lCont;
    
    template <class T_Cont>
    class CResourceAlloc{
    
    	T_Cont m_lEvents;
        
    public:
    	CResourceAlloc(void);
    	~CResourceAlloc(void);
    };
    

    Der Trick läuft unter SFINAE und wird durch das enable_if realisiert. So geht's mit boost:

    #include <vector>
    #include <utility>  // pair
    
    #include <boost/utility/enable_if.hpp>
    #include <boost/type_traits.hpp>    // is_same
    #include <boost/mpl/or.hpp>
    
    class CStateEvent;
    
    typedef std::vector<std::pair<double,CStateEvent*> > t_vCont;
    typedef std::vector<std::pair<double,CStateEvent*> > t_lCont;
    
    template <class T_Cont>
    class CResourceAlloc
    {
        typedef typename boost::enable_if< typename boost::mpl::or_< 
                typename boost::is_same< T_Cont, t_vCont>, 
                typename boost::is_same< T_Cont, t_lCont>
            >, T_Cont >::type container_type;
        container_type m_lEvents;
    
    public:
        CResourceAlloc();
        ~CResourceAlloc();
    };
    
    int main()
    {
        //CResourceAlloc< int > x;  // compiliert nicht
        CResourceAlloc< t_vCont > y;
        return 0;
    };
    

    (getestet mit VS2005 und boost 1.35)

    Leider funktioniert die Original-Variante (s.Kapitel 3.1) bei mir nicht, so ist es es eben doch ein (Compiler-)Fehler im Template, wenn man es mit einem anderen Typ versucht. Aber der Effekt ist der gewünschte - es compilieren nur die angegebenen Typen.

    Gruß
    Werner



  • Konstruktor und Destruktor von CResourceAlloc sollten vielleicht noch definiert werden.
    Dann läufts bei mir auch mit gcc und BCB2007. 🙂



  • .. mit dem VS2008 funktioniert es in der gewünschten Weise

    #include <vector>
    #include <utility>  // pair
    
    #include <boost/utility/enable_if.hpp>
    #include <boost/type_traits.hpp>    // is_same
    #include <boost/mpl/or.hpp>
    
    class CStateEvent;
    
    typedef std::vector<std::pair<double,CStateEvent*> > t_vCont;
    typedef std::vector<std::pair<double,CStateEvent*> > t_lCont;
    
    template< class T_Cont, class Enable = void >
    class CResourceAlloc;
    
    template <class T_Cont>
    class CResourceAlloc< T_Cont, typename boost::enable_if< typename boost::mpl::or_<
                typename boost::is_same< T_Cont, t_vCont>,
                typename boost::is_same< T_Cont, t_lCont>
            > >::type >
    {
        T_Cont m_lEvents;
    public:
        CResourceAlloc() 
            : m_lEvents()
        {}
        ~CResourceAlloc() {}
    };
    
    int main()
    {
        //CResourceAlloc< int > x;  // Zeile 32 compiliert nicht: 'x' uses undefined class 'CResourceAlloc<T_Cont>'
        CResourceAlloc< t_vCont > y;
        return 0;
    };
    

    .. und die Fehlermeldung - falls Zeile 32 aktiviert wird - kommt dann auch in dieser Zeile. So sollte es sein.

    Gruß
    Werner



  • Aber jetzt mal ganz ehrlich: warum will man denn so eine restriktion in templates überhaupt haben? Damit killt man sich doch das größte pro argument für templates: wiederverwendbarkeit.
    Templates sind eben nicht nur dafür da um sich schreibarbeit zu ersparen "ich will jetzt nicht für int und float dieselbe Klasse schreiben", sondern um das rad nicht andauernd neu erfinden zu müssen.

    Und viel bullshit kann man ohne solche restriktionen auch nicht machen. entweder es funktioniert, oder der compiler überschüttet einen mit kryptischen Fehlermeldungen. Was helfen die restriktionen dann?

    //edit und mir is grad aufgefallen, dass die beiden typen beim threadstarter identisch sind...ahm typedefs mit verschiedenen namen und gleichem typ stellen den gleichen typ dar. Warum also ÜBERHAUPT ein template hier?



  • otze schrieb:

    Templates sind eben nicht nur dafür da um sich schreibarbeit zu ersparen "ich will jetzt nicht für int und float dieselbe Klasse schreiben", sondern um das rad nicht andauernd neu erfinden zu müssen.

    Aber das geht ja so auch... Klar ist es nicht die Grundidee der Templates, ich selber finde die Lösung auch nicht unbedingt die schönste, aber ich mein ja nur...

    otze schrieb:

    Und viel bullshit kann man ohne solche restriktionen auch nicht machen. entweder es funktioniert, oder der compiler überschüttet einen mit kryptischen Fehlermeldungen. Was helfen die restriktionen dann?

    Naja, Hauptsache man kann kein Objekt erstellen (egal zu welchem Preis) :p

    otze schrieb:

    //edit und mir is grad aufgefallen, dass die beiden typen beim threadstarter identisch sind...ahm typedefs mit verschiedenen namen und gleichem typ stellen den gleichen typ dar. Warum also ÜBERHAUPT ein template hier?

    Rate mal, wie oft das in diesem Thread schon gesagt wurde 😉
    Irgendwie hat sich daraus eine allgemeine Diskussion über eingeschränkte Templates entwickelt.



  • Guten Morgen allerseits,

    hab mich bei den typedefs verschrieben, einmal vector, einmal list.

    ich wollte ne Eventklassen Verwaltung (was ich nicht näher erklären möchte) einmal mit nem Vector Container compilieren, und einmal mit nem List Container... aber es mit nem template zu machen ist egentlich schwachsinn, da ich damit nur ohne viel aufwand das ding mit unterschiedlichen container performancetechnisch testen wollte..



  • hola

    dann haettest das anders machen sollen:

    typedef std::pair<double,CStateEvent*> mypair;
    
    template<class T>
    class CResourceAlloc
    {
    	public:
    		typedef T container;
    		typedef container::iterator iterator;
    		typedef container::const_iterator const_iterator;
    		typedef container::size_type size_type;
    
    		container con;
    };
    
    CResourceAlloc<std::vector<mypair> > resource_alloc_vector;
    CResourceAlloc<std::list<mypair> > resource_alloc_list;
    

    hast jedoch unterschiedliche iterator-typen. also aufgepasst.

    Meep Meep



  • Werner Salomon schrieb:

    .. mit dem VS2008 funktioniert es in der gewünschten Weise[

    Das funktioniert auch mit dem BCB2007. Soweit standardkompatibel ist der also auch schon.



  • Werner Salomon: in diesem falle bräuchte man wohl eher SFIAE - substitution failure *is* an error... lieber auf static_assert warten und währenddessen BOOST_STATIC_ASSERT verwenden.


Anmelden zum Antworten