2009-12-05 7 views
8

J'ai une classe à base de modèle [Allotter.h & Allotter.cpp]:erreur Linker 'symbole externe non résolu': travailler avec des modèles

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; 
}; 

et son usage est affiché comme [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; 
}; 

Je ne montre pas les définitions complètes, car cela n'a pas vraiment d'importance. Le problème est quand je compile, tous les fichiers compilent correctement. Les fichiers sont dans un projet VC++. Plus tôt, lorsque je n'avais pas utilisé d'approche basée sur un modèle pour Allotter, tout était en train de compiler et de lier correctement. Mais maintenant, je reçois cette erreur:

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]@@@@QAEIPA[email protected]@@Z) referenced in function "private: void __thiscall ActiveListener::processConnections(void)" ([email protected]@@AAEXXZ) 

La chose surprenante est que le constructeur, ActiveListener::ActiveListener() ne fait aucune référence du tout Allotter<QTcpSocket>::Allotter(). La deuxième référence existe cependant. Mais je ne comprends pas pourquoi l'éditeur de liens n'est pas capable de résoudre ce symbole externe.

La sortie de la génération juste avant que les erreurs apparaissent est:

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... 

Je ne comprends pas si tout cela est pertinent, surtout parce que tout cela utilisé pour fonctionner parfaitement avant. C'est juste qu'après que j'utilise des modèles un problème est causé. Toute aide sera appréciée. Merci beaucoup.

+0

Merci à tous pour le montant de l'aide que vous avez fourni. J'ai fait un peu de recherche sur moi-même et j'ai trouvé une solution pour le même problème: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.13 Je le mets ici pour d'autres qui trébuchent ici à la recherche de solutions à des problèmes similaires. Merci encore: D –

+0

duplication possible de ["Erreur de lien" symboles non définis "avec la classe de modèle simple] (http://stackoverflow.com/questions/999358/undefined-symbols-linker-error-with-simple-template-class –

Répondre

16

Vous ne pouvez pas diviser les modèles en fichiers .h et .cpp - vous devez placer le code complet du modèle dans le fichier .h.

+5

Sauf si vous utilisez 'export', qui ne fonctionne que dans les contes de fées. –

+0

@Charles: 'export' fonctionne dans la vraie vie (avec le compilateur Comeau). –

+0

merci beaucoup pour cela: D Pourriez-vous m'expliquer pourquoi cela se produit? Je suppose que chaque fois que le compilateur a besoin d'une classe spécifique à partir d'un modèle, c'est-à-dire MyClass de MyClass , il doit avoir le code source pour générer la classe requise. Ai-je raison? –

1

Étant donné que vous ne pouvez pas placer l'implémentation de modèle dans des fichiers .cpp, il est recommandé d'utiliser des fichiers .inl pour l'implémentation de modèle et de les inclure à partir des en-têtes de modèle.

4

En règle générale, il est recommandé d'écrire le code de votre modèle entièrement dans les fichiers d'en-tête. Il existe une raison technique importante à cela: lorsque vous instanciez un modèle, le compilateur C++ doit générer du code à partir de ce modèle spécifique aux paramètres de modèle que vous avez spécifiés. Si le code de votre modèle est placé entièrement dans vos en-têtes, cela est fait pour vous automatiquement.

est est certainement possible d'écrire le code du modèle comme vous l'avez, avec l'implémentation placée dans les fichiers cpp. Si vous faites cela, cependant, vous devez instancier explicitement l'instance de modèle que vous avez l'intention d'utiliser.

Dans votre cas, vous devez ajouter la ligne suivante dans un fichier .cpp dans votre projet:

template class Allotter<QTcpSocket>; 
Questions connexes