La spécialisation des modèles échoue lors de la liaison

J’ai un problème avec la spécialisation des modèles que j’aimerais comprendre. Je travaille avec Visual C ++ 10.0 (2010). J’ai un cours comme celui-ci:

class VariableManager { public: template VarT get(std::ssortingng const& name) const { // Some code... } // This method supposed to be fully evaluated, linkable method. template std::string get(std::ssortingng const& name) const; private: std::map mVariables; }; 

En théorie, comme je me suis spécialisé dans la méthode “get”, l’éditeur de liens devrait pouvoir extraire un fichier object. Au lieu de cela, j’obtiens une erreur de référence non résolue avec l’éditeur de liens si je place la méthode dans le fichier source:

  template std::string VariableManager::get(std::ssortingng const& name) const { // Doing something... } 

Si je place cette méthode dans le fichier d’en-tête en ligne, la construction se passe bien. Je comprends que le modèle fonctionne comme ceci:

  template VarT get(std::ssortingng const& name) const; 

doit être placé dans l’en-tête car le compilateur ne pourra pas spécialiser le modèle en fonction du code appelant, mais dans le cas d’une spécialisation complète, c’est l’implémentation de la classe qui le fait; la méthode du modèle spécialisé devrait donc déjà exister en tant que symbole public. Quelqu’un pourrait-il apporter des éclaircissements sur cette question?

Votre parsing est correcte – un modèle de fonction explicitement spécialisé dans lequel les parameters de modèle spécifiés avec des valeurs explicites fournit une définition complète d’une fonction.

Si vous avez correctement inclus le fichier .cpp correspondant contenant la définition de la spécialisation explicite dans votre projet, VC ++ ne doit pas générer d’erreur de l’éditeur de liens. Pour ce qui est de la conformité aux normes, permettez-moi de noter que vous devez déclarer votre spécialisation en dehors de la classe englobante. La norme interdit de déclarer des spécialisations explicites à l’intérieur de la classe englobante (et les autres compilateurs rejetteront votre code). Alors changez le fichier d’en-tête pour déclarer la spécialisation comme ceci, à la place

 class VariableManager { public: template VarT get(std::ssortingng const& name) const { // Some code... } private: std::map mVariables; }; // This method supposed to be fully evaluated, linkable method. template<> std::string VariableManager::get(std::ssortingng const& name) const; 

Laissez-moi également noter que vous ne pouvez pas appeler get dans votre corps de classe. En effet, tout appel de ce type ne verrait pas encore la déclaration de spécialisation explicite et essaierait donc d’instancier la fonction à partir de la définition du modèle. La norme rend ce code mal formé, sans qu’un diagnostic soit requirejs.

La spécialisation d’un modèle ne force pas le compilateur à l’instancier (je pense que GCC le fait cependant); vous devez toujours indiquer explicitement au compilateur d’instancier réellement le modèle. Vous pouvez le faire avec une instanciation de modèle explicite. Fondamentalement, ajoutez simplement ceci dans le fichier source:

 template std::ssortingng VariableManager::get(const std::ssortingng& name) const; 

La méthode commençant par template<> est toujours considérée comme une méthode de spécialisation de template . Donc, vous devez avoir à mettre dans un fichier d’en-tête.

Si vous voulez le placer dans un fichier d’implémentation, vous devez le surcharger .

 class VariableManager { //... VarT get(std::ssortingng const& name) const {} std::ssortingng get(std::ssortingng const& name) const; //overloading not specialization };