2010-09-19 9 views
0

J'utilise Code :: Blocks pour générer mon projet, qui contient trois fichiers: main.cpp, TimeSeries.cpp, TimeSeries.h. TimeSeries.h fournit des déclarations de la classe TimeSeries comme suit:Référence non définie à ClassName :: ClassName

template<class XType, class YType> class TimeSeries { 
public: 
    TimeSeries(void); 
    ~TimeSeries(void); 
}; 

Puis TimeSeries.cpp contient: #include "TimeSeries.h"

template<class XType, class YType> 
TimeSeries<XType, YType>::TimeSeries(void) { 
} 

template<class XType, class YType> 
TimeSeries<XType, YType>::~TimeSeries(void) { 
} 

Et enfin, main.cpp contient

#include "TimeSeries.h" 
typedef TimeSeries<float, float> FTimeSeries; 

int main(int argc, char** argv) { 
    FTimeSeries input_data; 
    return 0; 
} 

Lors de la construction avec C :: B, j'obtiens l'erreur suivante:

undefined reference to `TimeSeries<float, float>::TimeSeries()' 

Que puis-je faire?

Merci,
CFP.

Répondre

2

La raison de la division du code en en-tête et en fichiers source est que la déclaration et l'implémentation sont séparées. Le compilateur peut traduire le fichier source (unité de compilation) en un fichier objet, et d'autres unités de compilation qui veulent utiliser les classes et fonctions incluent simplement le fichier d'en-tête et lient le fichier objet. De cette façon, le code doit être compilé une seule fois, et peut être réutilisé en le liant.

Le problème avec les modèles est que, tant qu'il n'y a pas de paramètres prévus pour eux, le compilateur ne peut pas les compiler. Le même modèle instancié avec différents paramètres donne des types différents. Sont, du point de vue des compilateurs, sans aucun rapport. Pour cette raison, les classes de modèles doivent généralement résider complètement dans un fichier d'en-tête, car lorsque le modèle est utilisé, le compilateur a besoin de la définition complète pour générer la classe en fonction des paramètres. Comme @Gabriel Schreiber l'a souligné dans his answer, vous pouvez dire au compilateur qu'il doit compiler le modèle avec un ensemble spécifique de paramètres, le rendant disponible à d'autres unités de compilation en liant simplement. Cependant, cela ne rend pas le modèle disponible pour d'autres jeux de paramètres.

+0

Merci pour votre réponse complète! –

3

Fondamentalement tout le code basé sur un modèle devrait être défini dans un en-tête, sinon il ne sera pas construit puisque rien ne l'utilise dans l'unité compilée.

Chaque fichier cpp est compilé en tant qu'unité distincte, et donc le constructeur et le destructeur ne sont pas compilés. Le compilateur n'a aucun moyen de savoir quel type d'argument de template vous utiliserez dans main.cpp quand il compilera TimeSeries.cpp.

+1

Donc, je mettrais tout le code dans le fichier d'en-tête? SOunds étrange, n'est-ce pas? –

+0

@CFP: Peut sembler étrange mais pour les gabarits, c'est (malheureusement) le chemin à parcourir. –

1

Vous devez ajouter dans votre .cpp fichier (ci-dessous les définitions):

template class TimeSeries<float, float>; 

Lorsque le compilateur compile TimeSeries.cpp il ne sait pas qui, pour quels types le modèle est nécessaire parce qu'il est utilisé dans un autre fichier source. Vous devez indiquer explicitement au compilateur.

En savoir plus sur l'instanciation de modèle explicite dans votre copie de Stroustrup ou sur Internet.

+0

Je vois, merci =) Mais cela tue la plupart du pouvoir des templates, n'est-ce pas? –