¿Por qué recibo errores de "símbolo externo no resuelto" cuando uso plantillas? [duplicar]


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 de origen (CPP) y un archivo de encabezado (H), obtengo muchos errores de "símbolos externos no resueltos" cuando se trata de vincular el ejecutable final, a pesar de que el archivo objeto esté correctamente construido e incluido en el enlace. ¿Qué está pasando aquí, y cómo puedo arreglarlo?

Author: dlanod, 2009-01-19

3 answers

Las clases y funciones templadas no se instancian hasta que se usan, normalmente en una instancia separada .archivo cpp (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 otro lugar y solo inserta la llamada a la función templada. Cuando se trata de compilar el archivo fuente de la plantilla, el tipo de plantilla específico que se está utilizando en la fuente del programa no se utiliza allí, por lo que aún no generará el código requerido para la función. Esto resulta en el símbolo externo sin resolver.

Las soluciones disponibles para esto son:

  1. incluir la definición completa de la función miembro en el archivo de cabecera de la plantilla y no tiene un archivo fuente para el plantilla
  2. definir todas las funciones miembro en el archivo fuente de la plantilla como "en línea", o
  3. definir el miembro funciones en el origen de la plantilla con la palabra clave "exportar". Desafortunadamente, esto no es compatible por muchos compiladores. (Actualización: esto se ha eliminado del estándar a partir de C++11.)

Tanto 1 como 2 básicamente abordan el problema dando al compilador acceso al código completo para la función templada cuando está intentando construya la función escrita en la fuente del programa.

 102
Author: dlanod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-12 01:46:46

Otra opción es poner 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 usar. Esto es útil si sabes que solo lo vas a usar para un par de tipos que conoces de antemano.

 12
Author: shoosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-19 06:46:44

Para cada archivo que incluya el .h archivo debe ser para 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 se olvide de colocar su clase de declaración entre las constantes de centinel

#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
 -2
Author: totem_motorist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-24 19:59:14