Templates (Sehen ,verstehen^^)



  • Erstens ist das, wo du ein template hinschreibst ein Klassentemplate und keine Templateklasse. (schwirrt irgendwo auch im FAQ rum..)
    Sie eigentlich keine Klassen und verhalten sich somit anders. Sie definieren eine Familie von Klassen, welche zur Kompilierzeit generiert werden. (Zur Vorstellung kannst du dir das so merken, dass der Compiler hingeht und für jeden Typen, den du irgendwann instanzierst eine Klasse erzeugt und die Templateargumente mit den angegeben Typen erzeugt).

    Die definitionen von Klassen gehören in den Header (oder die Datei muss vom Header inkludiert werden). Es gäbe das Schlüsselwort export, mit welchem es möglich wäre (sofern es ein Compiler unterstützt) die Definition in die .cpp zu verlagern. (ATM unterstützt das aber lediglich Comeau).

    Wenn du eine explizite Instanzierung hast, kannst du die Definition auch in die .cpp auslagern. (für Spezialisierungen)



  • das heißt es müsste dan so ausehen damit es mit der cpp funktioniert:

    // dat.hpp
    #ifndef DAT_HPP_
    #define DAT_HPP_
    
    template <class data>
    class DAT
    {
    private:
       data Var;
    public:
       extern data getData();
       extern bool isEmpty();
       extern void setData(data Wert);
    };
    
    #endif
    

    Ich verwende wxDev-C++.



  • Wikinger75 schrieb:

    das heißt es müsste dan so ausehen damit es mit der cpp funktioniert:

    Es beherrscht (soviel ich weiß) nur der Comeau C++ Compiler eine Variante des export [Template in Header/Source verteilt, ohne cpp-inklude aus dem Header] (weder dein wxDev-C++ noch MSVC++ etc. können dies)

    Templates schreibt man daher eigentlich immer komplett in den Header.



  • Was du machen kannst, ist folgendes:

    // dat.hpp
    #ifndef DAT_HPP_
    #define DAT_HPP_
    
    template <class data>
    class DAT
    {
    private:
       data Var;
    public:
       data getData();
       bool isEmpty();
       void setData(data Wert);
    };
    
    #inlcude "dat.impl"//Wichtige Stelle!!
    
    #endif
    
    // dat.impl
    using namespace std;//Verwende lieber std:: anstatt den Namespace komplett bekannt zu machen
    
    //----------> Getter! <----------//
    data DAT::getData()
    {
         return Var;
    }
    
    //----------> Prüfer! <----------//
    bool DAT::isEmpty()
    {
         if (Var == 0) {return true;}
         else {return false;}
    }
    
    //----------> Setter! <----------//
    void DAT::setData(data Wert)
    {
         Var = Wert;
    }
    
    //----------> TheEnd! <----------//
    


  • Firefighter schrieb:

    Was du machen kannst, ist folgendes:

    // dat.impl
    using namespace std;//Verwende lieber std:: anstatt den Namespace komplett bekannt zu machen
    

    Nicht nur besser. using namespace gehört niemals in eine Datei die includiert wird (in der Regel Header, in diesem Fall aber auch die Implementierung).



  • asc schrieb:

    Nicht nur besser. using namespace gehört niemals in eine Datei die includiert wird (in der Regel Header, in diesem Fall aber auch die Implementierung).

    ist das ein dogma?
    falls ja, widerspreche ich hiermit.



  • volkard schrieb:

    asc schrieb:

    Nicht nur besser. using namespace gehört niemals in eine Datei die includiert wird (in der Regel Header, in diesem Fall aber auch die Implementierung).

    ist das ein dogma?
    falls ja, widerspreche ich hiermit.

    Ganz ehrlich: Es gibt auch sinnvolle Regeln, und diese gehört dazu. Spätestens wenn man wegen einem unbedacht gesetzten using namespace Stundenlang in einem Projekt auf Fehlersuche ist, wird man dies merken.

    Bessonders schön sind da noch die Komponenten vom C++ Builder: Wozu werden überhaupt Namensräume definiert, wenn diese am Ende des gleichen Headers mittels using namespace wieder global veröffentlicht werden?



  • asc schrieb:

    Ganz ehrlich: Es gibt auch sinnvolle Regeln, und diese gehört dazu.

    Auch für sinnvolle Regeln gibt es sinnvolle Ausnahmen.
    Oder frei nach Simon2: Pauschalisierungen sind immer falsch! 😉

    asc schrieb:

    Bessonders schön sind da noch die Komponenten vom C++ Builder: Wozu werden überhaupt Namensräume definiert, wenn diese am Ende des gleichen Headers mittels using namespace wieder global veröffentlicht werden?

    Damit man im Kollisionsfalle den Namespace explizit angeben kann?

    Zu den Gründen für das automatisch generierte "using namespace" hatte ich hier etwas geschrieben.
    Wo ist der Nachteil in der Praxis?



  • audacia schrieb:

    asc schrieb:

    Ganz ehrlich: Es gibt auch sinnvolle Regeln, und diese gehört dazu.

    Auch für sinnvolle Regeln gibt es sinnvolle Ausnahmen.
    Oder frei nach Simon2: Pauschalisierungen sind immer falsch! 😉

    Gerade in einem Forum bei denen überwiegend Anfänger anfragen, finde ich sinnvolle Regeln besser. Das es immer Ausnahmen geben kann, mag sein. Ich gehe vom Regelfall der in 90% der Fälle sinnvoll ist aus (90:10 Regel).

    audacia schrieb:

    Zu den Gründen für das automatisch generierte "using namespace" hatte ich hier etwas geschrieben.
    Wo ist der Nachteil in der Praxis?

    Der Nachteil ist: Ich habe zwei verschiedene Komponenten die, die gleichen Bezeichner verwenden. Nach dem hinzufügen der zweiten durfte ich erstmal den gesamten Code überarbeiten. Dann lieber kein using namespace, um nicht irgendwann erstmal nach den Fehlern suchen zu dürfen.

    cu André



  • asc schrieb:

    Der Nachteil ist: Ich habe zwei verschiedene Komponenten die, die gleichen Bezeichner verwenden.

    Ob das using namespace nun im Header steht oder ob das der Autor der Komponente an den Anfang seiner .cpp-Datei setzt, ändert ja nun auch nichts 😉

    In der Tat wäre es aber ein reizvolles Refactoring, sämtliche Namen innerhalb einer Auswahl vollständig zu qualifizieren.



  • audacia schrieb:

    In der Tat wäre es aber ein reizvolles Refactoring, sämtliche Namen innerhalb einer Auswahl vollständig zu qualifizieren.

    Ich weiß, das gehört nicht zum Thread: Wann wird mein flehen nach mehr und vor allem auch funktionierenden Refactoringtools für den C++ Builder endlich erhört (Das eine das eh nicht funktioniert ist jedenfalls nicht ausreichend ;p).



  • Wenn alles gut läuft, in der kommenden Version, neben dem Class Explorer für C++.



  • #inlcude "dat.impl"//Wichtige Stelle!!
    

    muss die datei ".impl" heißen oder kann die auch anders heißen?



  • Wikinger75 schrieb:

    #inlcude "dat.impl"//Wichtige Stelle!!
    

    muss die datei ".impl" heißen oder kann die auch anders heißen?

    freier name.
    aber bei .impl weiß sogar ich, was damit gemeint ist. die implementierung von templatefunktionen, gell?



  • gut danke leute^^



  • asc schrieb:

    Ganz ehrlich: Es gibt auch sinnvolle Regeln, und diese gehört dazu.

    sinnvoll? nein, nicht mit fettem "niemals" drin.
    sobalds kein dogma mehr ist, geb ich dir recht.

    ich verwende entweder std oder vlib, aber ich will eigentlich nicht innerhalb eines projekts beide benutzen. da kann ich mir doch ein using namespace std oder using namespace vlib in den zentralen header knallen und dort umschalten.



  • ehm folegndes^^
    habs jetzt so:
    hpp

    // dat.hpp
    #ifndef DAT_HPP_
    #define DAT_HPP_
    
    template <class data>
    class DAT
    {
    private:
       data Var;
    public:
       data getData();
       bool isEmpty();
       void setData(data Wert);
    };
    
    #include "dat.impl"
    
    #endif
    

    impl

    // dat.impl
    
    //----------> Getter! <----------//
    data DAT::getData()
    {
         return Var; 
    }
    
    //----------> Prüfer! <----------//
    bool DAT::isEmpty()
    {
         if (Var == 0) {return true;}
         else {return false;}
    }
    
    //----------> Setter! <----------//
    void DAT::setData(data Wert)
    {
         Var = Wert;
    }
    
    //----------> TheEnd! <----------//
    

    Es gibt immer noch einen compiler fehler, auch wenn ich seh in h umbenene, naja werds wohl gleich in der hpp machen müssen^^



  • getData ist aber nicht in der klasse DAT, sondern in DAT<data>.
    das ging glaub ich so:

    template <class data> 
    data DAT<data>::getData()
    {
         return Var; 
    }
    

    aber bis auf seltene ausnahmen würde ich mich damit nicht behängen und den code einfach in die klasse kloppen.



  • ich habs jetzt aber in eine header gemacht so wie ich es vorhin geschrieben habe und es ging ohne das <data>.



  • Wikinger75 schrieb:

    muss die datei ".impl" heißen oder kann die auch anders heißen?

    Kann auch anders heissen. Neben .hpp und .h sieht man oft auch .inl, .ipp oder .impl. Ich bevorzuge persönlich .inl (für Inline), da hat MSVC gerade einen eigenen Datentyp.

    volkard schrieb:

    aber bis auf seltene ausnahmen würde ich mich damit nicht behängen und den code einfach in die klasse kloppen.

    Naja, ist auch ein wenig Geschmackssache. Ich mach oft eine Trennung, damit ich Schnittstelle und Implementierung sauber separiert habe. Auch wenn das manchmal auf komplizierte Funktionsdefinitionen herausläuft, gerade wenn noch ein typedef dabei ist... 😉

    P.S. Getter sollte man const machen, da man nichts an der Klasse verändert und somit die Memberfunktion auch mit konstanten Instanzen aufrufen kann.


Anmelden zum Antworten