2009-03-13 12 views
15

Ho un problema che non capisco davvero. Ho un nodo di classe.classe C++ con modello non riesce a trovare il suo costruttore

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

Questo è nel file "node.h". Nel file "node.cpp", c'è questo costruttore:

#include "node.h" 

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

Mentre il compilatore non trova alcun errore, il linker (ld) mi dice:

/usr/bin/ld: simboli indefiniti:

nodo <int> :: nodo (int)

la parte strana ... se sposto il costruttore dal file .cpp in .h, tutto funziona correttamente. Dov'è il problema?

risposta

23

Il problema è che i modelli non sono classi, di solito non li si scrive in due file separati. Le classi modello sono codice che il compilatore utilizza per generare classi. Di conseguenza, il codice di implementazione deve essere effettivamente in linea, ovvero nell'intestazione, come hai scoperto.

Per una spiegazione completa di perché deve essere in questo modo, vedere C++ FAQ Lite.

13

Come regola generale, è necessario inserire tutti i membri del modello all'interno del file di intestazione. I modelli sono compilati in base alle esigenze e quindi l'intera definizione deve essere disponibile ovunque venga utilizzata. Mettere il codice nel file di intestazione risolverà il problema.

L'unica volta che è possibile inserire una definizione di modello in un file CPP è quando il modello verrà utilizzato solo all'interno di tale file CPP. La ragione è che soddisfa lo standard che l'intera definizione è disponibile per la compilazione.

Lo spostamento del contenuto di node.cpp su node.h risolverà il problema.

Scenari Strani

Poi di nuovo, si può anche mettere tutto in un file CPP e includere il file CPP. Il C++ è flessibile in questo modo. Lo dico solo perché l'ho già visto prima. In realtà ho ferito la mia mascella quando ha colpito la parte superiore della mia scrivania.

+1

Si può anche mettere funzioni membro templatized di una classe non templatized nel file cpp se si è mai andare a chiamarli altrove (in modo da far rispettare questo, dovrebbe essere privato, ma non devono essere). – rmeador

1

Quando si utilizza , è probabile che non sia incluso node.cpp. Pertanto, il compilatore non può creare un'istanza del costruttore node<int>::node<int>. Di solito si inserisce tutto il codice del modello, incluse tutte le implementazioni dei metodi, nel file di intestazione o qualcosa incluso da esso.

0

A meno che non ci sia una chiamata alla funzione, il compilatore non produrrà alcun codice e il linker non lo troverà.

Si dovrebbe inserire la funzione nell'intestazione a cui appartiene.

+0

Ancora non capisco. Perché il modello non può essere una classe, con intestazione separata e il codice sorgente? Diciamo che voglio scrivere la mia lista .. devo includere ogni metodo List nel file di intestazione? –

+0

Sì, questo è il modo più comune. Puoi anche #includere "List.cpp" nella parte inferiore di List.h. –

+0

ok allora. Ho trovato strano includere tutto nel file di intestazione: il codice effettivo è un po 'più lungo delle poche righe nella domanda (è un albero di ricerca binario). –

0

esemplificazione implicita è spento, è necessario

template class node<int>; 

da qualche parte nel codice (node.cpp forse)

EDIT: risposta cattiva, non è probabilmente il caso.

+1

Se pensi che questa sia una cattiva risposta, puoi cancellarla prima di ridurla. –

1

La pratica comunemente accettata consiste nel mettere tutta l'implementazione nel file .h, in modo che le classi possano essere generate dal modello secondo necessità.

Se si conosce in anticipo quale tipo di modello verrà istanziato con, si potrebbe essere in grado di imbrogliare un po '. Assicurati che il tuo .cpp includa un caso d'uso per ogni tipo e metodo di cui avrai bisogno. È importante che il caso d'uso venga dopo il codice del modello. Per esempio. per "node.cpp", utilizzare

#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>; 
Problemi correlati