Fehler bei Compilieren meines Projektes. (LNK2019)



  • Heyho liebe Foren-Mitglieder,

    vlt. kann mir hier jemand helfen?
    Ich habe eine Template Klasse erstellt und in eine Header und cpp Klasse aufgeteilt. In meiner main.cpp verwende ich die Funktionen aus der Template Klasse.

    Nun erhalte ich doch beim Compilieren den Fehler:
    LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: void __thiscall Reihe<int,5>::setDaten(int,int)" (?setDaten@?$Reihe@H$04@@QAEXHH@Z)" in Funktion "_main"
    ...
    Insgesamt taucht dieser Fehler 5 mal mit jeder Funktion, die ich in der Main nutze auf. kann mir einer vlt. weiterhelfen?

    Anbei die fraglichen cpp Dateien.

    // ----------------------- Reihe.h -------------------------------------------
    #pragma once
    #include<iostream>
    
    using namespace std;
    
    template<typename T =  int, int MAX = 5>
    class Reihe
    {
    
    private:
    	T daten[MAX]{ 0 };
    
    public:
    	//!!!! Mit Zeigern oder Referenzen arbeiten!!
    	void setDaten(const T& d, int index);
    	T& getDaten(int index);
    	T& operator[](int index);
    	int getSize();
    
    };
    // ----------------------------------------------------------
    // ------------------------------- Reihe.cpp -----------------------------------
    #include"Reihe.h"
    
    
    
    using namespace std;
    
    template <typename T, int MAX> void Reihe<T, MAX>::setDaten(const T& d, int index)
    {
        this.daten[index] = d;
    }
    
    template <typename T, int MAX> T& Reihe<T, MAX>::getDaten(int index) 
    {
        return daten[index];
    }
    
    template<typename T, int MAX> int Reihe<T, MAX>::getSize()
    {
    	return MAX;
    }
    
    template <typename T, int MAX> T& Reihe<T, MAX>::operator[](int index) {
        if (index >= MAX) {
            cout << "Pufferueberlauf!!!\n";
            return daten[MAX - 1];
        }
        else if (index < 0) {
            cout << "Pufferunterlauf!!!\n";
            return daten[0];
        }
        return daten[index];
    }
    //-----------------------------------------------
    // ------------------------------------ main.cpp --------------------------
    #include<iostream>
    
    #include"Reihe.h"
    
    using namespace std;
    
    int main()
    {
    	Reihe<int> intis;
    	for (int i = 0; i < intis.getSize(); i++) {
    		intis.setDaten(i, i);
    	}
    	for (int i = 0; i < intis.getSize(); i++) {
    		cout << intis.getDaten(i) << endl;
    	}
    	Reihe<double, 10> doublis;
    	for (int i = 0; i < doublis.getSize(); i++) {
    		double dval = 0.5 + i;
    		doublis[i] = dval;
    	}
    	for (int i = 0; i < doublis.getSize(); i++) {
    		cout << doublis[i] << endl;
    	}
    
    	// Testen der Methode zum Pufferüber-/unterlauf
    	cout << doublis[10] << endl;
    	cout << doublis[-1] << endl;
    
    	return 0;
    }
    


  • Template-Definitionen müssen immer als Source der Kompilierungseinheit ("translation unit") bekannt sein, d.h. zwingend im Header (bzw. von der Headerdatei eingebunden) sein.



  • @Th69 Vielen Dank, dass erklärt natürlich mein Problem 🙂
    Gibt es da einen technischen Grund für, dass man das hier nicht splitten kann wie bei anderen Klassen?



  • Da kann ich dich nur auf den englischen Artikel FAQ: Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file? verweisen.

    Es gab mal den Versuch mit dem Schlüsselwort export, aber dies hatte nur ein Kompilerhersteller umgesetzt und war entsprechend schwierig und wurde daher wieder aus dem C++ Standard entfernt.

    Edit: Mit dem neuen C++20 Modulsystem wird es dann aber einfacher: C++20: Further Open Questions to Modules - Templates and Modules



  • Du hast keine Template Klasse, sondern ein Template, eine Vorlage.
    Eine konkrete Klasse wird daraus erst bei Instanzierung mit Argumenten für die Template-Parameter; wenn die Definition in einer eigenen cpp-Datei ist, mit welchem Datentyp, bzw. welchen Datentypen sollen da Klassen erstellt werden, wenn diese cpp-Datei kompiliert wird?



  • Wenn du deine Template-Definitionen trotzdem von den Deklarationen trennen willst kannst du auch einfach eine neue Datei erstellen, ich denke die Dateiendung ist hierbei egal, aber ich hab da immer was mit .impl verwendet.

    Dann tust du die Definitionen in deine .impl Datei und inkludierst diese im Header direkt unterhalb deiner Deklarationen.

    Sollte funktionieren.



  • @Th69 sagte in Fehler bei Compilieren meines Projektes. (LNK2019):

    Template-Definitionen müssen immer als Source der Kompilierungseinheit ("translation unit") bekannt sein, d.h. zwingend im Header (bzw. von der Headerdatei eingebunden) sein.

    Vielleicht etwas genauer: Kompilierungseinheit muss in der Lage sein die gewünschte Template-Instanz (z.B. Reihe<int>) zu verwenden. Entweder, indem der Compiler diese in der Übersetzungseinheit selbst generieren kann (dazu muss der Template-Source der Definition bekannt sein, z.B. via Header-Include) ODER verwendeten Instanzen müssen gelinkt werden.

    Fun fact:

    Letzteres erlaubt eine etwas unorthodoxere Lösung für das Problem: Man kann die Template-Definition überraschenderweise sehr wohl in die Reihe.cpp packen, wenn man die benötigten Template-Instanzen dort entweder ebenfalls verwendet oder explizit instantiiert:

    // Reihe.cpp
    
    ...
    
    template class Reihe<int>;
    template class Reihe<double, 10>;
    

    ... und diese dann dazu linkt. Nicht getestet, sollte aber funktioneren. Ist natürlich nicht sehr flexibel, da man vorher festlegen muss, für welche T Instanzen erzeugt werden.

    Das braucht man auch nicht sehr häufig, daher reicht es, sich als Anfänger das mit dem "Template-Code in den Header" zu merken.


Log in to reply