Templates in header - wie mittels eigener datei includen?



  • Hallo,

    da templates ja im header stehen müssen wollte ich übersicht walten lassen und die implementierungen in einer extra datei tragen die dann in den header includiert wird. Nur müsste das doch genau in der Klasse stehen z.B unter public....aber da kann ihc ja nichteinfach ein #include my_templates.h machen bzw. wie macht man das normalerweise?



  • du kannst im grunde includes ueberall hinpacken.
    Wenn Klassentemplates ausserhalb der definition implementiert werden sollen, wird es oft so geamcht, dass die Datei mit der Implementierung nach der definition includiert wird:

    //file wuppdich.h
    #ifndef wuppdich_h
    #define wuppdich_h
    
    template<class T>
    class Wuppdich
    {
    int x;
    public:
      void foo();      //nur deklariert, definition kommt in der ausgelagerten Datei
      int bar();
    };
    
    #include Wuppdich_Impl.hxx  //viele nehmen andere fileendungen als .h oder .cpp
                                //ACHTUNG: dieser include muss innerhalb des includeguards stehn
    #endif
    
    //file Wuppdich_Impl.hxx
    template<class T>
    void Wuppdich<T>::foo() { x = 42; }
    
    template<class T>
    int Wuppdich<T>::bar() { return x; }
    

    Das ist eigentlich alles.



  • Und jetzt einmal tief durchatmen und dann von vorne anfangen - was ist dein Problem?

    Bei Templates mußt du normalerweise die Definition direkt im Header angeben in der Form:

    template<typename T>
    class test
    {
      test() {cout << "Ctor\n";}
      ...
    };
    

    Wenn du die Definitionen auslagern willst, kannst du die zuständige Definitionsdatei auch am Ende des Headers einbinden:

    //test.h
    template<typename T>
    class test
    {
      test();
      ...
    };
    #include "test.imp"//der Name ist zwar egal, aber um den Compiler nicht zu verunsichern, solltes du kein .CPP nehmen
    
    //test.imp
    template<typename T>
    inline test<T>::test()
    { cout<<"Ctor\n"; }
    


  • Darf ich mal fragen, welchen Vorteil man da durch hat? (ernste frage!)



  • Ein User, der sich deinen Header mit der Definition des Klassentemplates durchliest, wird nicht von Meterweise code erschlagen. Natuerlich kann man statt die Implementierung zu includieren sie auch gleich hintenan bappen. Tricky koennte es auch werden, wenn du Plattformspezifische Implementierungen hast, denn es sieht uebersichtlicher aus, wenn da ein

    #ifdef UNIX
    #include Wuppdich_UnixImpl.inc
    #elif defined(WIN32)
    #include Wuppdich_Win32Impl.inc
    #endif

    steht als wenn der code fuer alle Plattformen zwischen verstreuten praeprozessordirektiven in derselben file steht

    PS: bitte nicht schlagen wenn die Makronamen falsch sind, hab da noch nie mit gearbetet >)



  • @CStoll: Warum benutzt du inline vor dem konstruktor? Falls sinnvoll - sollte man das vor jeder template funktion benutzen?

    Und was ist der Unterschied zwischen template<class T> ....und template<typename T>

    UNd wenn man jetzt manche template funktionen private und public anlegen will - muss man dazu 2 Impl. files anlegen weil ich kann ja nur ein include machen?

    ??

    danke


  • Mod

    Mati schrieb:

    @CStoll: Warum benutzt du inline vor dem konstruktor? Falls sinnvoll - sollte man das vor jeder template funktion benutzen?

    Vermutlich aus Gewohnheit. Und für gewöhnlich auch nicht sinnvoll.

    Und was ist der Unterschied zwischen template<class T> ....und template<typename T>

    keiner. Reine Geschmacksfrage.



  • Danke

    also template funktionen kann ich jetzt in ne .imp datei verpflanzen.
    wie geht ihr so vor - wohin schreibt ihr z.B template-spezialisierungs-funktionen
    also sowas wie:

    Class<double>::my_method() {...} ?
    Auch in die .imp datei oder eher dann in die .cpp datei?

    danke



  • Mati schrieb:

    @CStoll: Warum benutzt du inline vor dem konstruktor? Falls sinnvoll - sollte man das vor jeder template funktion benutzen?

    Hauptsächlich zum Schutz gegen ODR-Fehler (der Header könnte ja mehrfach im Projekt auftauchen und dann hat man plötzlich zwei Definitionen der selben Funktion)

    Und was ist der Unterschied zwischen template<class T> ....und template<typename T>

    Syntaktisch keiner - ich verwende grundsätzlich 'typename', weil class mehr nach "nur selbstdefinierte Klassen erlaubt" klingt.

    UNd wenn man jetzt manche template funktionen private und public anlegen will - muss man dazu 2 Impl. files anlegen weil ich kann ja nur ein include machen?

    Nein, die kannst du auch alle in eine .IMP legen.

    PS: Template-Spezialisierungen sind vollständige Definitionen und gehören darum in eine eigene CPP (oder hinter ein 'inline').



  • CStoll schrieb:

    Und was ist der Unterschied zwischen template<class T> ....und template<typename T>

    Syntaktisch keiner - ich verwende grundsätzlich 'typename', weil class mehr nach "nur selbstdefinierte Klassen erlaubt" klingt.

    Ich halt mich da auch sher an die Literatur, wo oft "typename" verwendet wird, wenn alles erlaubt ist, und "class", wenn nur Benutzerdefinierte Klassen erlaubt sind. Letzteres bedeutet meist, dass die Implementierung sich auf Details der Klasse verlaesst (z.B. bei Policies, oder darauf, dass ein operator() vorliegt bei functoren etc). So kann der Leser schon aus der Deklaration sehen, welche Templateparameter Einschraenkungen unterliegen.

    CStoll schrieb:

    PS: Template-Spezialisierungen sind vollständige Definitionen und gehören darum in eine eigene CPP (oder hinter ein 'inline').

    Natuerlich nur, wenn es sich um vollstaendige Spezialisierungen handelt 😉



  • pumuckl schrieb:

    CStoll schrieb:

    Und was ist der Unterschied zwischen template<class T> ....und template<typename T>

    Syntaktisch keiner - ich verwende grundsätzlich 'typename', weil class mehr nach "nur selbstdefinierte Klassen erlaubt" klingt.

    Ich halt mich da auch sher an die Literatur, wo oft "typename" verwendet wird, wenn alles erlaubt ist, und "class", wenn nur Benutzerdefinierte Klassen erlaubt sind. Letzteres bedeutet meist, dass die Implementierung sich auf Details der Klasse verlaesst (z.B. bei Policies, oder darauf, dass ein operator() vorliegt bei functoren etc). So kann der Leser schon aus der Deklaration sehen, welche Templateparameter Einschraenkungen unterliegen.

    Aber zu sehr sollte man sich darauf nicht verlassen - schließlich sieht der Compiler keinen Unterschied zwischen beidem.

    (historisch war 'class' älter, um zu kennzeichnen, daß der Parameter ein Datentyp ist. typename wurde später ergänzt, um in Templates unterscheiden zu können zwischen Werten und Typen ( typename vector<T>::iterator pos; oder typename It_type::value_type tmp; ) - und dann fiel wohl jemandem auf, daß es auch klarer für Template-Parameterlisten verwendet werden könnte.)

    CStoll schrieb:

    PS: Template-Spezialisierungen sind vollständige Definitionen und gehören darum in eine eigene CPP (oder hinter ein 'inline').

    Natuerlich nur, wenn es sich um vollstaendige Spezialisierungen handelt 😉

    Ja, soviel ist klar - ich war bei meiner Aussage auch von Mati's "Class<double>::" Beispiel ausgegangen - und das ist eine vollständige Spezialisierung.


Anmelden zum Antworten