Fehler bei Template-Spezialisierung



  • Hi,
    ich habe folgendes Problem:

    Das Hauptprogramm "fehler.cpp" inkludiert die template-Definition "template_header.h". Es gibt auch eine andere Compilierungseinheit "unit2.cpp" , die "unit2.h" inkludiert, die wiederum "template_header.h" inkludiert. Der Linker beschwert sich, dass die Funktion clone doppelt definiert ist:

    fehler.cpp:

    #include "template_header.h"
    int main() {return 0;}
    

    unit2.cpp:

    #include "unit2.h"
    void f () {}
    

    unit2.h:

    #ifndef BESP_unit2_h
    #define BESP_unit2_h
    #include "template_header.h"
    // andere Deklarationen, die Inhalt von template_header benoetigen
    #endif
    

    template_header.h:

    #ifndef BESP_template_header_h
    #define BESP_template_header_h
    template <class T>
    T* clone(T* tp) { /*mach was*/ return tp; }
    template <>
    int* clone (int* sp) { // <== Linker Error: multiple definition of `int* clone<int>(int*)'
       //mach was anderes
       return sp;
    }
    #endif
    

    Wenn ich die template-Spezialisierung template <>
    int* clone ... unter Kommentar setze funktioniert alles tadellos.

    Was mache ich falsch ??? Das template ist tatsächlich doppelt definiert, einmal in fehler.o und einmal in unit2.o. Ich würde daher verstehen, wenn der Linker auch nach dem Auskommentieren der template-Spezialisierung Fehler meldet, das tut er aber nicht ...

    Ich verwende den gcc-Compiler unter Ubuntu 7.10, der die Template-Spezialisierungen an sich kann.



  • Du verletzt die ODR. genau das Thema hatten wir vor einigen Minuten in einem anderen Thread: http://www.c-plusplus.net/forum/viewtopic-var-t-is-205771-and-postdays-is-0-and-postorder-is-asc-and-start-is-15.html



  • Danke !! Ich verstehe aber nicht, was die "explizite" Templatespezialisierung sein soll, von der dort die Rede ist. Oder besser gesagt: Gibt es denn auch eine implizite Templatespezialisierung ???

    Und kann mir jemand einen Tipp geben, wie/ wo ich die Templatespezialisierung am besten definieren soll, damit die ODR nicht verletzt wird ?



  • Nein, implizite Spezialisierung gibts nicht, explizite Templatespezialisierung bedeutet vollstaendige Spezialisierung (im Gegensatz zu partieller Spezialisierung, die es fuer Funktionen aber so nicht gibt).

    Wenn ich das richtig verstanden habe musst du spezialisierte Funktionstemplates entweder inline deklarieren (eine mehrfach definierte inline-Funktion verletzt die ODR nicht, und spezialisierte Funktionstemplates werden wie normale Funktionen behandelt), oder du packst die Definition der Spezialisierung in eine eigene Uebersetzungseinheit:

    //// template_header.h
    #ifndef BESP_template_header_h
    #define BESP_template_header_h
    template <class T>
    T* clone(T* tp) { /*mach was*/ return tp; }
    #endif
    
    /// template_spezi.cpp
    #include template_header.h
    template <>
    int* clone (int* sp) { 
       //mach was anderes
       return sp;
    };
    

    So kannst du den header trotzdem ueberall einbinden, musst aber darauf achten, dass die template_spezi.o mitgelinkt wird, da sonst die nicht-spezialisierte Version instantiiert wird wenn jemand clone<int> aufruft. (eventuell kann man das durch static_assert verhindern)



  • Vielen Dank !!!! 🙂


  • Mod

    pumuckl schrieb:

    So kannst du den header trotzdem ueberall einbinden, musst aber darauf achten, dass die template_spezi.o mitgelinkt wird, da sonst die nicht-spezialisierte Version instantiiert wird wenn jemand clone<int> aufruft. (eventuell kann man das durch static_assert verhindern)

    Es genügt nicht, diese Übersetzungseinheit mit der Definition mitzulinken. Die Spezialisierung muss auch in jeder anderen Übersetzungseinheit deklariert werden (sonst würde diese Spezialisierung ja in den anderen Übersetzungseinheiten aus dem Primärtemplate instantiiert werden - wie üblich keine Diagnose erforderlich).

    //// template_header.h
    #ifndef BESP_template_header_h
    #define BESP_template_header_h
    template <class T>
    T* clone(T* tp) { /*mach was*/ return tp; }
    template <>
    int* clone (int* sp); // wichtig
    #endif
    
    /// template_spezi.cpp
    #include template_header.h
    template <>
    int* clone (int* sp) {
       //mach was anderes
       return sp;
    };
    

Anmelden zum Antworten