2009-12-05 4 views
8

Ich habe eine Vorlage basiert Klasse [Allotter.h & Allotter.cpp]:Linker-Fehler 'nicht aufgelöstes externes Symbol': Arbeiten mit Vorlagen

template <typename allotType> class Allotter { 
public: 
Allotter(); 
quint32 getAllotment(allotType*); 
bool removeAllotment(quint32, int auto_destruct = 0); 

private: 
QVector<QPair<quint32, allotType*>> indexReg; 
int init_topIndex; 
}; 

und es ist Nutzung ist als [ActiveListener.h & ActiveListener. cpp]:

class ActiveListener: public QObject { 
Q_OBJECT 

public: 
ActiveListener(); 

private slots: 
    void processConnections(); 
    void readFromSocket(int); 

private: 
QTcpServer* rootServer; 
QSignalMapper* signalGate; 
Allotter<QTcpSocket> TcpAllotter; 
}; 

Ich zeige nicht die vollständigen Definitionen, da es nicht wirklich wichtig ist. Das Problem ist, wenn ich kompiliere, alle Dateien richtig kompilieren. Die Dateien befinden sich in einem VC++ - Projekt. Früher, als ich keinen Vorlagen-basierten Ansatz für Allotter verwendet habe, war alles Kompilieren und Verknüpfen in Ordnung. Aber jetzt bekomme ich diesen Fehler:

1>ActiveListener.obj : error LNK2019: unresolved external symbol "public: __thiscall Allotter<class QTcpSocket>::Allotter<class QTcpSocket>(void)" ([email protected]@@@@[email protected]) referenced in function "public: __thiscall ActiveListener::ActiveListener(void)" ([email protected]@[email protected]) 
1>ActiveListener.obj : error LNK2019: unresolved external symbol "public: unsigned int __thiscall Allotter<class QTcpSocket>::getAllotment(class QTcpSocket *)" ([email protected][email protected]@@@@[email protected]@@Z) referenced in function "private: void __thiscall ActiveListener::processConnections(void)" ([email protected]@@AAEXXZ) 

Die überraschende Sache ist, dass der Konstruktor, ActiveListener::ActiveListener() keinen Hinweis auf allen Allotter<QTcpSocket>::Allotter() macht. Die zweite Referenz existiert jedoch. Aber ich verstehe nicht, warum der Linker dieses externe Symbol nicht auflösen kann.

Die Build-Ausgabe, kurz bevor die Fehler angezeigt ist:

1>Moc'ing ActiveListener.h... 
1>Compiling... 
1>stdafx.cpp 
1>Compiling... 
1>ActiveListener.cpp 
1>Allotter.cpp 
1>moc_ActiveListener.cpp 
1>main.cpp 
1>Generating Code... 
1>Linking... 

Ich verstehe nicht, wenn irgendetwas davon relevant ist, vor allem, weil alles perfekt bevor sie zur Arbeit eingesetzt. Es ist nur so, dass nach der Verwendung von Vorlagen ein Problem verursacht wird. Jede Hilfe wird geschätzt. Danke vielmals.

+0

Vielen Dank an alle für die Höhe der Hilfe, die Sie zur Verfügung gestellt haben. Ich recherchierte ein wenig selbst und fand eine Lösung für das gleiche Problem: http://www.parashift.com/c++faq-lite/templates.html#faq-35.13 Ich setze es hier für andere, die hier zufällig auf der Suche nach Lösungen für ähnliche Probleme stolpern. Nochmals vielen Dank: D –

+0

möglich duplicate von ["Undefined symbols" Linker Fehler mit einfachen Template-Klasse] (http://stackoverflow.com/questions/999358/undefined-symbol-linker-error-with-simple-template-class) –

Antwort

16

Sie können Vorlagen nicht in .h- und .cpp-Dateien aufteilen. Sie müssen den vollständigen Code für die Vorlage in die .h-Datei einfügen.

+5

Es sei denn du benutzt 'export', was nur in Märchen funktioniert. –

+0

@Charles: 'export' funktioniert im wirklichen Leben (mit dem Comeau-Compiler). –

+0

vielen Dank dafür: D Könnten Sie mir nur erklären, warum das passiert? Ich nehme an, dass, wann immer der Compiler eine bestimmte Klasse aus einer Vorlage benötigt, d. H. MyClass von MyClass , muss der Quellcode die erforderliche Klasse generieren. Bin ich richtig? –

1

Da Sie die Vorlagenimplementierung nicht in CPP-Dateien platzieren können, wird empfohlen, .INL-Dateien für die Vorlagenimplementierung zu verwenden und sie aus den Vorlagenheadern aufzunehmen.

4

Im Allgemeinen gilt es als bewährte Methode, den Vorlagencode vollständig in die Header-Dateien zu schreiben. Es gibt einen wichtigen technischen Grund dafür: Wenn Sie eine Vorlage instanziieren, muss der C++ - Compiler Code aus dieser Vorlage generieren, die für die von Ihnen angegebenen Vorlagenparameter spezifisch ist. Wenn Ihr Vorlagencode vollständig in Ihren Kopfzeilen platziert ist, geschieht dies automatisch für Sie.

Es ist ist definitiv möglich, Vorlagencode die Art zu schreiben, die Sie haben, mit der Implementierung in cpp-Dateien platziert. Wenn Sie dies jedoch tun, müssen Sie die Vorlageninstanz, die Sie verwenden möchten, explizit instanziieren.

In Ihrem Fall müssen Sie die folgende Zeile in eine CPP-Datei in einem Projekt hinzuzufügen:

template class Allotter<QTcpSocket>; 
Verwandte Themen