2009-12-05 21 views
8

He una clase basada en plantillas [Allotter.h & Allotter.cpp]:error de vinculador 'símbolo externo sin resolver': trabajar con plantillas

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

y es de uso se muestra como [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; 
}; 

No estoy mostrando las definiciones completas, ya que realmente no importa. El problema es que cuando compilo, todos los archivos se compilan correctamente. Los archivos están en un proyecto de VC++. Antes, cuando no usaba un enfoque basado en plantillas para Allotter, todo estaba compilando y enlazando bien. Pero ahora, me sale este error:

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) 

Lo sorprendente es, que el constructor, ActiveListener::ActiveListener() no hace ninguna referencia en absoluto Allotter<QTcpSocket>::Allotter(). La segunda referencia sin embargo existe. Pero no entiendo por qué el enlazador no puede resolver este símbolo externo.

El resultado de generación justo antes de que aparezcan errores es:

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

No entiendo si algo de esto es relevante, sobre todo porque todo esto solía funcionar perfectamente antes. Es solo que después de usar plantillas, se produce un problema. Cualquier ayuda será apreciada. Muchas gracias.

+0

Gracias a todos por la cantidad de ayuda que nos ha facilitado. Hice un poco de investigación de mi mismo y he encontrado un poco una solución para el mismo problema: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.13 lo estoy poniendo aquí para otros que tropiezan aquí buscando soluciones a problemas similares. Gracias de nuevo: D –

+0

posible duplicado de [error de enlazador "Símbolos no definidos" con clase de plantilla simple] (http://stackoverflow.com/questions/999358/sunfined-symbols-linker-error-with-simple-template-class) –

Respuesta

16

No se puede dividir en archivos de plantillas .hy .cpp - que necesita para poner el código completo de la plantilla en el archivo .h.

+5

A menos que uses 'export', que solo funciona en los cuentos de hadas. –

+0

@Charles: 'export' funciona en la vida real (con el compilador Comeau). –

+0

muchas gracias por eso: D ¿Podría explicarme por qué sucede eso? Supongo que siempre que el compilador necesite una clase específica de una plantilla, es decir, MyClass de MyClass , necesita tener el código fuente para generar la clase requerida. ¿Estoy en lo cierto? –

1

Como no se puede colocar la aplicación plantilla en archivos .cpp, se considera una buena práctica utilizar los archivos .INL para la ejecución de la plantilla y ellos incluyen desde las cabeceras de plantilla.

4

En términos generales se considera la mejor práctica para escribir su código de la plantilla en su totalidad dentro de los archivos de cabecera. Hay una razón técnica importante para esto: cuando crea una instancia de una plantilla, el compilador de C++ necesita generar código a partir de esa plantilla que sea específica para los parámetros de la plantilla que ha especificado. Si su código de plantilla se coloca por completo en sus encabezados, esto se hace automáticamente.

Es es definitivamente es posible escribir el código de la plantilla de la manera que usted tiene, con la implementación colocada en archivos cpp. Sin embargo, si hace esto, debe crear una instancia explícita de la instancia de la plantilla que tiene la intención de utilizar.

En su caso, es necesario agregar la siguiente línea en un archivo .cpp en su proyecto:

template class Allotter<QTcpSocket>; 
Cuestiones relacionadas