c++ - ¿Por qué obtengo errores de "símbolo externo no resuelto" cuando uso plantillas?
templates linker (3)
Esta pregunta ya tiene una respuesta aquí:
Cuando escribo código C ++ para una clase usando plantillas y divido el código entre un archivo fuente (CPP) y un archivo de cabecera (H), recibo un montón de errores de "símbolos externos no resueltos" cuando se trata de vincular el ejecutor final, a pesar de que el archivo objeto está correctamente construido e incluido en el enlace. ¿Qué está pasando aquí y cómo puedo solucionarlo?
Las clases y funciones con plantilla no se instancian hasta que se utilizan, normalmente en un archivo .cpp separado (por ejemplo, la fuente del programa). Cuando se utiliza la plantilla, el compilador necesita el código completo para que esa función pueda construir la función correcta con el tipo apropiado. Sin embargo, en este caso, el código para esa función se detalla en el archivo fuente de la plantilla y, por lo tanto, no está disponible.
Como resultado de todo esto, el compilador simplemente asume que está definido en otra parte y solo inserta la llamada a la función de plantilla. Cuando se trata de compilar el archivo fuente de la plantilla, el tipo de plantilla específica que se está utilizando en el origen del programa no se usa allí, por lo que aún no generará el código requerido para la función. Esto da como resultado el símbolo externo sin resolver.
Las soluciones disponibles para esto son:
- incluir la definición completa de la función miembro en el archivo de encabezado de la plantilla y no tener un archivo fuente para la plantilla,
- definir todas las funciones miembro en el archivo fuente de la plantilla como "en línea", o
-
defina las funciones de miembro en la fuente de la plantilla con la palabra clave "exportar".Lamentablemente, esto no es compatible con muchos compiladores.(Actualización: esto se ha eliminado del estándar a partir de C ++ 11 ).
Ambos, 1 y 2, básicamente resuelven el problema al dar acceso al compilador al código completo para la función de plantilla cuando está intentando construir la función tipeada en el origen del programa.
Otra opción es colocar el código en el archivo cpp y en el mismo archivo cpp agregar instancias explícitas de la plantilla con los tipos que espera utilizar. Esto es útil si sabes que solo vas a usarlo para un par de tipos que conoces de antemano.
Para cada archivo que incluya el archivo .h, debe insertar ambas líneas:
#include "MyfileWithTemplatesDeclaration.h"
#include "MyfileWithTemplatesDefinition.cpp"
muestra
#include "list.h"
#include "list.cpp" //<---for to fix bug link err 2019
int main(int argc, _TCHAR* argv[])
{
list<int> my_list;
my_list.add_end(3);
.
.
}
Además, no olvide colocar su clase de declaración entre las constantes de centinela
#ifndef LIST_H
#define LIST_H
#include <iostream>
.
.
template <class T>
class list
{
private:
int m_size,
m_count_nodes;
T m_line;
node<T> *m_head;
public:
list(void);
~list(void);
void add_end(T);
void print();
};
#endif