web-dev-qa-db-fra.com

Erreur de référence non définie pour la méthode du modèle

Cela me rend fou depuis une heure et demie. Je sais que c'est une petite chose, mais je ne trouve pas ce qui ne va pas (le fait que c'est un vendredi après-midi pluvieux, bien sûr, n'aide pas).

J'ai défini la classe suivante qui contiendra les paramètres de configuration lus dans un fichier et me permettra d'y accéder depuis 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 est assez simple. Mais quand je teste depuis mon programme principal en utilisant

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

J'obtiens une erreur de compilation undefined reference to 'int VAConfig::convert<int>...'. Idem pour readParameter().

J'ai regardé beaucoup de tutoriels sur les modèles mais je ne pouvais pas le comprendre. Des idées?

44

L'implémentation de code modèle ne doit jamais être dans un .cpp fichier: votre compilateur doit les voir en même temps qu'il voit le code qui les appelle (sauf si vous utilisez instanciation explicite pour générer le code objet modèle, mais même alors .cpp n'est pas le bon type de fichier à utiliser).

Ce que vous devez faire est de déplacer l'implémentation dans le fichier d'en-tête ou dans un fichier tel que VAConfig.t.hpp, puis #include "VAConfig.t.hpp" chaque fois que vous utilisez des fonctions membres basées sur des modèles.

70
Seth Johnson

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 de fonctions modèles aux points où elles sont instanciées.

10
dma

Une méthode modèle n'est qu'un modèle ... pour une méthode. Les arguments du modèle doivent être remplis là où la méthode est "instanciée".

Il devrait être possible de construire 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èle" compiler toutes les instances nécessaires de la méthode de modèle.

Ce n'est pas le cas pour le vc de Microsoft. J'ai entendu un collègue murmurer que c'était le cas sur Unix, cependant.

La plupart des compilateurs instancient la méthode du 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 modèle. C'est pourquoi le corps est le plus souvent placé soit dans le fichier d'en-tête, soit dans par ex. un fichier .h.cpp, qui est ensuite inclus comme dernière ligne du fichier .h.

5
xtofl