Eigene Vektorklasse verursacht Linkerror



  • sry, nix... ^^



  • Natürlich, bin ja nicht auf den Kopf gefallen 😉

    #include <Vector.hpp>
    
    template <typename T, int iMax>
    CVector<T, iMax>::CVector(void)
    {
    	this->m_iCurrent = 0;
    	this->m_iMax = iMax;
    
    	for (int i = 0; i < this->m_iMax; i++)
    	{
    		this->m_arrValues[i] = NULL;
    	}
    }
    
    template <typename T, int iMax>
    void CVector<T, iMax>::push(T Value)
    {
    	if (this->m_iCurrent >= this->m_iMax)
    	{
    		m_pTools->log("Vector ist bereits komplett gefuellt");
    		return;
    	}
    
    	this->m_arrValues[this->m_iCurrent++] = Value;
    }
    
    template <typename T, int iMax>
    void CVector<T, iMax>::pushTop(T Value)
    {
    	if (this->m_iCurrent >= this->m_iMax)
    	{
    		m_pTools->log("Vector ist bereits komplett gefuellt");
    		return;
    	}
    
    	if (this->m_iCurrent)
    	{
    		for (int i = this->m_iCurrent - 1; i >= 0; i--)
    		{
    			this->m_arrValues[i + 1] = this->m_arrValues[i];
    		}
    	}
    
    	this->m_arrValues[0] = Value;
    }
    
    template <typename T, int iMax>
    T CVector<T, iMax>::pop(int iIndex)
    {
    	if (iIndex >= this->m_iCurrent)
    	{
    		m_pTools->log("Vector hat nur %i Eintraege", this->m_iCurrent);
    		return;
    	}
    
    	// to be continued...
    }
    
    template <typename T, int iMax>
    T CVector<T, iMax>::popValue(T Value)
    {
    	int iIndex = this->find(Value);
    
    	if (iIndex >= 0)
    	{
    		this->pop(iIndex);
    	}
    }
    
    template <typename T, int iMax>
    void CVector<T, iMax>::popAll(void)
    {
    	for (int i = 0; i < this->m_iCurrent; i++)
    	{
    		this->m_arrValues[i] = NULL;
    	}
    
    	this->m_iCurrent = 0;
    }
    
    template <typename T, int iMax>
    int CVector<T, iMax>::find(T Value)
    {
    	for (int i = 0; i < this->m_iCurrent; i++)
    	{
    		if (T == this->m_arrValues[i])
    		{
    			return i;
    		}
    	}
    
    	m_pTools->log("Vector Eintrag konnte nicht gefunden werden");
    
    	return -1;
    }
    
    template <typename T, int iMax>
    int CVector<T, iMax>::count(void)
    {
    	return this->m_iCurrent;
    }
    

    Gruß



  • Und das steht in welcher Datei?
    Hoffentlich auch in der Header Datei, oder in einer cpp, inl, oder wie auch immer die in die Header Datei eingebunden wird.

    Simon



  • theliquidwave schrieb:

    #include <Vector.hpp>
    
    template <typename T, int iMax>
    CVector<T, iMax>::CVector(void)
    {
    	this->m_iCurrent = 0;
    	this->m_iMax = iMax;
    	
    	for (int i = 0; i < this->m_iMax; i++)
    	{
    		this->m_arrValues[i] = NULL;
    	}
    }
    
    ...
    

    Ja und nun? Ist doch klar wie Kloßbrühe, warum das nicht geht. Hat SeppJ ja auch schon erklärt.



  • Btw:
    Der richtige std::vector benutzt einen abgekapselten Memory-Allocator (std::allocator). Sollteste vielleicht auch nutzen 😉



  • Hi.
    Also erstmal danke für die Antworten. Aber ich sehe da nichts, was falsch ist?! Wo fehlt denn da eine "Templatedefinition"? Ich definiere die Klasse doch in der Headerdatei und packe den Code dann in die C++-Datei - wie immer. Ist das etwa falsch?

    Tut mir leid dass ich da nichts erkenne, aber für mich ist das Neuland.

    @ Kóyaánasqatsi: Das ist mir zu kompliziert ^^ Da müsste ich mich erst einmal reinarbeiten. Ich will sowas ja auch selber probieren 😉

    Gruß



  • Ich definiere die Klasse doch in der Headerdatei und packe den Code dann in die C++-Datei - wie immer. Ist das etwa falsch?

    Ja.

    template<typename T> class vector; // Klassen-Template-DeKLARAtion
    
    template<typename T> class vector  // Klassen-Template-DeFINItion
    {
      T *beg, *end, *cap;
    public:
      vector();  // DeKLARAtion des Konstruktors
      ...
    };
    
    template<typename T>
    vector<T>::vector()       // DeFINItion des Konstruktors
    : beg(0), end(0), cap(0)
    {}
    

    Wenn Du die DeFINItion des Konstruktors des Klassentemplates in Übersetzungseinheit A versteckst und Du für ein bestimmtes T den aus der Übersetzungseinheit B aufrufen willst, kann zum Zeitpunkt der Kompilierung von ÜE B kein Code für den Konstruktor generiert werden, da ja die DeFINItion unbekannt ist --> Linkerfehler. Lösung: Dem Compiler muss die DeFINItion des Konstruktors bekannt sein, wenn ÜE B kompiliert wird. Die "Eine-Definition-Regel" erlaubt Mehrfachdefinitionen (höchstens eine pro ÜE) von Klassen, Klassentemplates, inline-Funktionen, Funktionstemplates, Elementfunktionen von Klassentemplates und statische Datenelemente von Klassentemplates (mag sein, dass ich noch etwas vergessen habe), sofern die Definition "dieselbe" ist. Von daher ist es auch nicht schlimm, wenn Du die Definition in einen Header packst und den Header in mehreren ÜEs einbindest.

    Die Trennung von Deklaration und Definition für Templates in versch ÜEs wird zwar vom Standard erlaubt, erfordert aber 1. das export Schlüsselwort und 2. einen Compiler, der export auch versteht und verarbeiten kann. Unterstützung für "exported templates" bieten aber die meisten Compiler nicht und man denkt sogar darüber nach, export wieder aus dem C++ Standard zu schmeißen, weil's sich als "schwierig umsetzbar" herausgestellt hat. Man würde sich damit der Realität wieder annähern.

    Gruß,
    SP



  • Ui!
    Danke für die ausführliche Erklärung 🙂
    Habe es jetzt (hoffe ich) verstanden und es nun gelöst 😉

    Gruß


  • Mod

    theliquidwave schrieb:

    Aber ich sehe da nichts, was falsch ist?! Wo fehlt denn da eine "Templatedefinition"? Ich definiere die Klasse doch in der Headerdatei und packe den Code dann in die C++-Datei - wie immer. Ist das etwa falsch?

    Zum wiederholten Male: Ja, das ist falsch! Bei Templates funktioniert das so nicht. Der Compiler kann aus einem Template keinen Objektcode erzeugen - ist ja nur eine Vorlage für Programmcode. Die Templateparameter müssen bekannt sein, damit Code erzeugt werden kann. Daher wird aus deiner c++-Datei genau Nichts erzeugt. Und daher findet der Linker später keinen Code den er linken kann.

    Sind dir die Begriffe "Deklaration", "Definition", "Compiler" und "Linker" eigentlich vollständig klar? Ich habe den Eindruck, dass du dich da nicht so genau mit auskennst. Falls das so ist, frag ruhig mal nach.



  • Ich definiere die Klasse doch in der Headerdatei und packe den Code dann in die C++-Datei - wie immer. Ist das etwa falsch?

    Ja!

    s. den Artikel http://www.c-plusplus.net/forum/viewtopic-var-t-is-128361.html insbesondere Punkt 7 "Das Schlüsselwort export".


Anmelden zum Antworten