C2491, Templates und DLLImport



  • Hallo zusammen,

    ich habe gerade versucht eine Klasse für eine Art Array-Handler zu schreiben, welches im ersten Projekt als DLL verpackt wird, die vom zweiten Projekt verwendet werden soll. Das Problem im zweiten Projekt ist jedoch zuerst folgendes gewesen:

    Ich hatte versucht die Klasse mit Hilfe von Templates etwas flexibler im Bezug auf Datentypen zu machen. Als ich nun versuchte die DLL und die Klasse zu verwenden, bekam ich einen Linkerfehler geworfen, der wohl den Ursprung hatte, dass ich die Methodendefinition in der Header und somit in der Klasse untergebracht hatte. Die Methodendeklaration jedoch hingegen in einer CPP-Datei, also getrennt voneinander. Nach etwas hin und her lesen bekam ich raus, dass die Template-Methoden in der Header-File mit deklariert werden müssen. Gesagt, getan und zack! Der nächste Fehler, aus dem ich nun nicht ganz schlau werde, was aber wohl etwas mit meinem DLLImport zu tun hat.

    Folgender Fehler tritt auf:

    gbarray.h(64): error C2491: 'gbArray<T>::gbArray': Definition von Funktion für dllimport nicht zulässig
    gbarray.h(77): error C2491: 'gbArray<T>::~gbArray': Definition von Funktion für dllimport nicht zulässig
    gbarray.h(89): error C2491: 'gbArray<T>::operator []': Definition von Funktion für dllimport nicht zulässig
    

    Die Klasse sieht wie folgt aus:

    template <class T>
    class MY_API gbArray
    {
    	protected:
    	private:
    		//	Variables
    		T * mArray;
    		int mRows, mCols;
    
    	public:
    		//	(De-)Constructor & Copy
    		gbArray(int pRows, int pCols);
    		~gbArray();
    
    		//	Operators
    		T * operator[](int pIndex);
    };
    

    Darunter die Funktionen:

    template <class T>
    gbArray<T> :: gbArray(int pRows, int pCols)
    {
    	...
    }
    
    template <class T>
    gbArray<T> :: ~gbArray()
    {
    	...
    }
    
    template <class T>
    T * gbArray<T> :: operator[](int pRow)
    {
    	...
    }
    

    Laut MSDN bedeutet das:

    Data, static data members, and functions can be declared as dllimports but not defined as dllimports.

    Also heißt dass, das ich die Methoden nicht in der Header deklarieren darf?
    Aber was ich daran nicht ganz verstehe ist, dass ich sie ja in der Klasse definiere, die mit MY_API gekennzeichnet ist und erst später (weiter unterhalb der Klasse) deklariere?

    Weiß jemand Rat?

    Beste Grüße und vielen Dank,
    SKiD.



  • SkiD schrieb:

    ...der wohl den Ursprung hatte, dass ich die Methodendefinition in der Header und somit in der Klasse untergebracht hatte. Die Methodendeklaration jedoch hingegen in einer CPP-Datei, also getrennt voneinander...

    Du hast in der .cpp deklariert und im header definiert? Hö?

    SkiD schrieb:

    Nach etwas hin und her lesen bekam ich raus, dass die Template-Methoden in der Header-File mit deklariert werden müssen

    Also wenn das 1. Snippet die Header ist und das 2. die cpp, dann machst du das doch garnicht? So wie ich das sehe ist dein Classtemplate nicht das Funktionstemplate, weil du das nochmal getrennt angibst. T im Konstruktor ist nicht das T, dass du für die Klasse benutzt, ist das so gewollt? Oder sehe ich das falsch, bin mit templates nicht so vertraut, benutze meist generics.



  • Oh man, was habe ich denn da geschrieben. DX

    Also ich hatte die Methoden in der Headerdatei deklariert und in der CPP definiert. So rum, ich hatte es nur falsch herum aufgeschrieben.

    Zum Problem:
    Das erste Snippet ist der Ausschnitt meiner Klasse, die Templates verwendet mit der Deklaration meiner Methoden. Das zweite Snippet ist direkt unterhalb der Klasse und zeigt die Definition der Template-Methoden und somit der Methoden der Klasse. Es gibt somit keine CPP-Datei mehr.

    Ich habe mittlerweile herausgefunden, dass ein DLLImport/Export nicht möglich ist von Templates. Jedoch können Instanzen exportiert werden. Nun habe ich mich gefragt, welchen anderen Weg es gäbe, eine Klasse verwendbar als nur für einen Datentyp zu gestalten?

    Also die Funktionen nutzen den Typ, der bei der Erstellung eines Objektes mit angegeben wird. Beispielsweise so:

    template <class T>
    class cTemplate {
        T mValue;
      public:
        cTemplate (T pValue){ mValue = pValue; }
    };
    
    int main()
    {
      ...
      cTemplate <int> tObject(115);
      ...
    }
    

    Können Generics denn exportiert werden?
    Was ist denn genau der Unterschied zu Templates?



  • Templates müssen vor dem Compilieren initialisiert sein, es ist nicht möglich während der Laufzeit ein Objekt von einer Klasse, dass templates benutzt, dynamisch zu erstellen. Das ist der Unterschied zu generics, die auch erst während der Laufzeit initialisiert werden können. Oder auf Deutsch: Wenn du ein Objekt einer Klasse anlegst oder eine Funktion aufrufst und es sind templates im Spiel, muss klar sein, welchen Typ du dabei benutzt, bevor das Programm compiliert wird. Bei generics kann der Typ auch er während das Programm "läuft" festgelegt werden.

    Können Generics denn exportiert werden?

    Ja. Eben weil der Typ zur Compiletime nicht fetstehen muss.

    Btw:
    template:

    template <class T>
    class cTemplate {
    };
    

    managed generic:

    generic <class T>
    class cTemplate {
    };
    

Anmelden zum Antworten