2009-07-10 6 views
36

Cela me rend fou depuis une heure et demie. Je sais que c'est une petite chose mais ne peux pas trouver ce qui ne va pas (le fait que c'est un vendredi après-midi pluvieux, bien sûr, n'aide pas).Erreur de référence non définie pour la méthode de gabarit

J'ai défini les paramètres classe suivante qui configuration tiendra lecture d'un fichier et me permettra d'y accéder de mon programme:

class VAConfig { 
    friend std::ostream& operator<<(std::ostream& lhs, const VAConfig& rhs); 

private: 
    VAConfig(); 
    static std::string  configFilename; 
    static VAConfig*  pConfigInstance; 
    static TiXmlDocument* pXmlDoc; 
    std::map<std::string, std::string> valueHash; 

public: 
    static VAConfig* getInstance(); 
    static void setConfigFileName(std::string& filename) { configFilename = filename; } 
    virtual ~VAConfig(); 

    void readParameterSet(std::string parameterGroupName); 
    template<typename T> T readParameter(const std::string parameterName); 
    template<typename T> T convert(const std::string& value); 
}; 

où la méthode convert() est définie dans VAConfig.cpp comme

template <typename T> 
T VAConfig::convert(const std::string& value) 
{ 
    T t; 
    std::istringstream iss(value, std::istringstream::in); 
    iss >> t; 
    return t; 
} 

Tout à fait simple. Mais quand je test de mon programme principal à l'aide

int y = parameters->convert<int>("5"); 

Je reçois une erreur de compilation undefined reference to 'int VAConfig::convert<int>...'. Idem pour readParameter().

A regardé beaucoup de tutoriels de modèle, mais je ne peux pas comprendre cela. Des idées?

+2

Une heure et demie, c'est pas si mal ... ça m'a tué pour 3 hier. –

Répondre

55

mise en œuvre du code basé sur des modèles ne devrait jamais être dans un fichier .cpp: votre compilateur doit les voir en même temps qu'il voit le code qui les appelle (sauf si vous utilisez explicit instantiation pour générer le code objet basé sur un modèle, mais même alors .cpp est le mauvais type de fichier à utiliser). Ce que vous devez faire est de déplacer l'implémentation vers le fichier d'en-tête ou vers un fichier tel que VAConfig.t.hpp, puis #include "VAConfig.t.hpp" chaque fois que vous utilisez des fonctions membres modélisées.

+0

Merci Seth et Dominic, j'ai déplacé les implémentations dans le fichier d'en-tête et cela a fonctionné. Je n'ai jamais vu cet aspect mentionné dans un tutoriel que j'ai lu. Alors, pourquoi le compilateur a-t-il besoin de voir l'implémentation en même temps qu'il voit le code qui les appelle, c'est-à-dire, qu'est-ce qui rend les fonctions de templates uniques à cet égard? – recipriversexclusion

+2

Le compilateur doit disposer de la définition complète du modèle lorsqu'il l'instancie, de sorte qu'il puisse substituer les paramètres du modèle et l'évaluer. Si votre compilateur le prend en charge, vous pouvez déclarer votre modèle comme "extern" et l'utiliser comme vous le feriez pour n'importe quel autre membre, au prix d'un travail de lien supplémentaire. GCC supporte cela comme une extension. Cela va faire partie de la norme C++ 0x. – greyfade

+0

Il existe des techniques pour conserver les modèles à l'écart, à savoir, la transmission en avant des spécialisations de modèle. -1 pour "ne devrait jamais" –

9

Si vous déplacez l'implémentation des méthodes basées sur des modèles (convert et readParameter) vers le fichier d'en-tête, cela devrait fonctionner.

Le compilateur doit avoir accès aux implémentations des fonctions de modèle aux points où elles sont instanciées.

5

Une méthode de modèle est simplement un modèle pour une méthode. Les arguments du modèle doivent être remplis lorsque la méthode est "instanciée".

Il devrait être possible de compiler un compilateur qui se contente de la déclaration d'une méthode de modèle, et d'avoir une étape de 'compilation de modèles' compiler toutes les instances nécessaires de la méthode modèle.

Ce n'est pas le cas pour Microsoft vc. J'ai entendu un collègue marmonner à ce sujet étant le cas sur unix, cependant.

La plupart des compilateurs instancient la méthode de modèle sur demande, où ils sont utilisés dans le code source. Afin d'instancier la méthode, le compilateur doit 'voir' le corps de la fonction template. C'est pourquoi le corps est le plus souvent placé soit dans le fichier d'en-tête, soit par ex. un fichier .h.cpp, qui est ensuite inclus en tant que dernière ligne du fichier .h.

+0

Ce que vous décrivez est un "modèle externe". Il est inclus dans la prochaine version de la norme C++ et a été pris en charge par GCC depuis longtemps (en tant qu'extension). Visual C++ devrait le supporter dans la version bêta actuelle de la prochaine version. – greyfade

+0

@greyfade: Merci! – xtofl

+0

.h.cpp ou .hpp? – Naveen

Questions connexes