Frage zur compilierung von Templates



  • Ich bin neu beim Thema Templates und verstehe noch nicht ganz wie ich folgendes schaffe:

    Ich habe eine Datei in der ich auf eine generalisierte Klasse und deren Methoden zugreife. Der Datei ist die Deklaration der template-Klasse bekannt, sie bindet jedoch NICHT direkt ihre Definition ein.
    Die Definition der Template-Klasse wird getrennt compiliert.
    Soweit so gut, nun das Problem:
    Wie erzeuge ich die spezialisierte Form der Templates-Klasse für meinen Fall?
    Ich kann ja nicht einfach die beiden Libraries zusammen linken, da mir die Spezialisierung fehlt, und der Linker meckert das er eine undefinierte Referenz gefunden hat.
    Ich habe gedacht das dafür das Schlüsselwort export ist, aber g++ sagt das es nicht implementiert ist.

    Code Beispiel:

    //blub.hpp
    template<class T>
    class Blub {
        public:
    	T t;
    	T get();
    };
    
    //blub.cpp
    #include "blub.hpp"
    
    template<class T>
    T Blub<T>::get() { return t; }
    
    //test.cpp
    #include <iostream>
    #include "blub.hpp"
    
    int main() {
        Blub<int> blub;
        std::cout << blub.get();
        return 0;
    }
    

    Konsole:

    $ g++ -c blub.cpp
    $ g++ -c test.cpp
    $ g++ test.o blub.o
    test.o: In function `main':
    test.cpp:(.text+0x11): undefined reference to `Blub<int>::get()'
    collect2: ld returned 1 exit status
    $
    


  • LeggaLasagne schrieb:

    Ich habe eine Datei in der ich auf eine generalisierte Klasse und deren Methoden zugreife. Der Datei ist die Deklaration der template-Klasse bekannt, sie bindet jedoch NICHT direkt ihre Definition ein.
    Die Definition der Template-Klasse wird getrennt compiliert.
    Soweit so gut, nun das Problem

    Nein, soweit so schlecht. Da das Schlüsselwort export von kaum einem Compiler unterstützt wird, musst du Templates vollständig in Headerdateien definieren.





  • Ah, ich war mir natürlich mal wieder zu fein in die FAQ zu schauen. 🤡
    Dadurch verliert man dann natürlich den Vorteil, die Klassen-definition getrennt von ihrer Anwendung zu compilieren, d.h. immer wenn ich was am Template ändere, muss ich auch die Komplette Anwendungs-Datei neu compilieren, oder irre ich mich?

    Hier braucht man im Gegensatz zu icht-Templates keine Angst vor Mehrfachdefinitionen in verschiedenen Headern zu haben, der Linker erkennt Templateklassen und -funktionen und ignoriert die zusätzlichen Definitionen.

    Warum ist der Linker nicht so schlau und bemerkt das auch bei normalen Klassen und Funktionen, anstatt sich über multiple Definitionen zu beschweren?



  • LeggaLasagne schrieb:

    Dadurch verliert man dann natürlich den Vorteil, die Klassen-definition getrennt von ihrer Anwendung zu compilieren, d.h. immer wenn ich was am Template ändere, muss ich auch die Komplette Anwendungs-Datei neu compilieren, oder irre ich mich?

    Nein, du hast Recht. Das ist in der Tat ein Problem. Man kann sich zwar Header und Implementierung immer noch trennen, indem man die Definitionen in eine .inl-Datei schreibt und diese am Ende des Schnittstellen-Headers inkludiert, aber bei Änderungen der Implementierung muss der abhängige Code neu kompiliert werden.

    LeggaLasagne schrieb:

    Warum ist der Linker nicht so schlau und bemerkt das auch bei normalen Klassen und Funktionen, anstatt sich über multiple Definitionen zu beschweren?

    Sofern du die Methoden inline definierst, ist das kein Problem. Aber das empfiehlt sich wegen der genannten Abhängigkeiten nicht – hier hat man im Gegensatz zu Templates ja die Wahl. Ausserdem ist auch die Kompilierzeit höher, wenn die gesamte Implementierung jedes Mal von neuem geparst werden muss.


Anmelden zum Antworten