2009-03-13 12 views
15

Tengo un problema que realmente no entiendo. Tengo un Nodo de clase.C++ clase con plantilla no puede encontrar su constructor

template<class T> 
class node { 
protected: 
    T _data; 
public: 
    node(T data); 
}; 

Esto está en el archivo "node.h". En el archivo "node.cpp", no es este constructor:

#include "node.h" 

template<class T> 
node<T>::node (T data) { 
    _data = data; 
} 

Mientras que el compilador no encuentra ningún error, el enlazador (ld) me dice:

/usr/bin/ld: símbolos no definidos:

nodo <int> :: node (int)

la parte extraña ... si muevo el constructor de .cpp a archivo .h, todo funciona bien. ¿Dónde está el problema?

Respuesta

23

El problema es que las plantillas no son clases; normalmente no las escribe en dos archivos separados. Las clases de plantilla son código que el compilador usa para generar clases. Como tal, su código de implementación debe estar efectivamente en línea, es decir, en el encabezado como descubrió.

Para una explicación más completa de por qué tiene que ser de esta manera, vea el C++ FAQ Lite.

13

Como regla general, debe poner todos los miembros de la plantilla dentro del archivo de encabezado. Las plantillas se compilan según su uso y, por lo tanto, toda la definición debe estar disponible donde sea que se usen. Poner el código en el archivo de encabezado resolverá ese problema.

La única vez que puede poner una definición de plantilla en un archivo CPP es cuando la plantilla solo se utilizará dentro de ese archivo CPP. La razón es que cumple con el estándar de que toda la definición está disponible para compilación.

Mover los contenidos de node.cpp a node.h solucionará el problema.

escenarios extraños

Por otra parte, también se puede poner todo en un archivo CPP e incluya el archivo CPP. C++ es flexible de esta manera. Solo menciono esto porque lo he visto hecho antes. De hecho, me lastimé la mandíbula cuando golpeó la parte superior de mi escritorio.

+1

También se puede poner a plantillas funciones miembro de una clase no a plantillas en el archivo CPP si nunca va a llamar en otro lugar (por lo que cumplir esto, debe ser privado, pero no tienen que serlo). – rmeador

1

Cuando usanode<int>, probablemente no haya incluido node.cpp. Por lo tanto, el compilador no puede crear instancias del constructor node<int>::node<int>. Por lo general, pone todo el código de plantilla, incluidas todas las implementaciones de los métodos, en el archivo de encabezado o algo incluido a partir de él.

0

A menos que haya una llamada a la función, el compilador no generará ningún código y el vinculador no lo encontrará.

Debe poner la función en el encabezado al que pertenece.

+0

Todavía no lo entiendo. ¿Por qué la plantilla no puede ser una clase, con encabezado separado y el código fuente? Digamos que quiero escribir mi propia lista .. ¿Tengo que incluir cada método de lista en el archivo de encabezado? –

+0

Sí, esa es la forma más común. También puede #incluir "List.cpp" en la parte inferior de List.h. –

+0

bien entonces. Me pareció extraño incluir todo en el archivo de encabezado; el código real es un poco más largo que las pocas líneas de la pregunta (es un árbol de búsqueda binario). –

0

instanciación implícita está apagado, necesita

template class node<int>; 

en algún lugar de su código (node.cpp tal vez)

EDIT: mala respuesta, que probablemente no es el caso.

+1

Si cree que esta es una respuesta incorrecta, puede eliminarla antes de recibir una votación negativa. –

1

La práctica comúnmente aceptada es poner toda la implementación en el archivo .h, para que las clases se puedan generar a partir de la plantilla, según sea necesario.

Si sabe con anticipación con qué tipos se creará una instancia de su plantilla, es posible que pueda hacer trampa un poco. Solo asegúrese de que su .cpp incluya un caso de uso para cada tipo y método que necesite. Es importante que el caso de uso venga después del código de la plantilla. P.ej. para "node.cpp", utilice

#include "node.h" 

template<class T> 
node<T>::node (T data) { 
    _data = data; 
} 

void dummy(void) 
{ 
    node<int> intnode(0); 
    node<double> doublenode(0.0); 
} 
1
// You can put templates declaration in header and definition in source 
// node.h or wherever you include file gets included 
extern template class node<int>; 

// node.cpp or where ever source file you want to use it 
// But use it only once for each type of generated class 
template class node<int>; 
Cuestiones relacionadas