2010-12-15 101 views
13

Je sais qu'il me manque quelque chose de facile ici mais j'ai une fonction de membre modélisée d'une classe que j'ai spécialisée.spécialisation de modèle multipliez les symboles définis

MyClass 
{ 
    template<typename T> T GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s); 
} 

template<typename T> 
T MyClass::GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    throw std::runtime_error("Don't know how to convert " + ToString(v->GetString())); 
} 

template<> 
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    return v->GetInteger(); 
} 

template<> 
string MyClass::GetTFromVariable<string>(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    return v->GetString(); 
} 

// etc for other specialisations. 

Ceci est défini dans mon fichier d'en-tête (en tant que modèles devraient être), mais quand je vais et compilent je reçois un tas de symboles mutliply définis, un représentant une telle erreur est:

 OtCustomZenith_logic.lib(PtPathOutput.obj) : error LNK2005: "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall MyClass::GetTFromVariable<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(class boost::shared_ptr<class TOtSimpleVariable>,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" ([email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@[email protected]@[email protected]@Z) already defined in TableFareSystem_test.obj 

je peux corrigez-le en indiquant les méthodes mais je ne pense pas que cela soit nécessaire ... qu'est-ce que j'ai oublié?

EDIT: J'utilise Visual Studio 2010

+0

Quelle toolchain utilisez-vous? GCC? Quelque chose de visuel? Si GCC, à quoi ressemblent les lignes de construction et de liaison? –

Répondre

23

Comme Alf a noté, la spécialisation complète n'est plus un modèle. Cependant, je ne suis pas sûr que a à définir en ligne. Vous devriez également pouvoir diviser la déclaration et la définition.

I.e. Dans votre tête ont:

template<> 
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s); 

et dans la mise en œuvre ont:

template<> 
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    return v->GetInteger(); 
} 

J'avais aussi pensé que par les droits de la définition basé sur un modèle doit aussi être explicitement en ligne (je l'ai toujours fait), mais ne serait pas trop surpris si un compilateur donné était laxiste dans l'application de l'ODR pour les modèles. Je serais intéressé de voir la référence standard qui stipule le contraire.

+1

Je suis désolé pour le libellé imprécis. Je parlais seulement du code OP tel qu'il était/est présenté, avec la définition dans le fichier d'en-tête. Merci de clarifier! Cheers, –

+0

déplacer la spécialisation de l'en-tête à un seul fichier .cpp implique la nécessité de compiler et de lier à un .obj ou .lib nuire à la convivialité. mieux vaut le garder en ligne comme suggéré par @alf. Je suis en train de voter votre réponse à cause de cela. –

23

La spécialisation complète n'est plus un modèle. C'est une fonction concrète. En tant que tel, il doit être déclaré (implicitement ou explicitement) inline. Le plus simple est d'ajouter ce mot clé avant la spécification du type de retour.

Cela dit, le code présenté ne correspond pas à votre message d'erreur.

Votre message d'erreur parle de type de retour std::string, pas le type de retour int.

Vive & HTH.,

+0

"Votre message d'erreur parle du type de retour' std :: string', pas du type de retour 'int'." ... ce qui signifie qu'il utilise le premier modèle (général), qui renvoie le type T (dans ce cas, 'std :: string'). –

+1

@Mike: non, cela signifie que le code présenté ne correspond pas au message d'erreur. Je pourrais * deviner * que l'OP a plusieurs spécialisations explicites, pas seulement une, et qu'il a choisi un message d'erreur arbitraire. mais ce serait juste une supposition.Je dis, quand vous demandez de l'aide, essayez d'être précis, ne pas introduire des questions non pertinentes. –

+0

Merci @alf, vous étiez correct et j'ai mis à jour la question pour refléter plus précisément le problème. –

2

Je vous suggère de supprimer la mise en œuvre suivante à partir de votre code tout à fait, de sorte que le compilateur peut générer des erreurs à la compilation elle-même si T est pas int. La détection précoce des erreurs est meilleure que la détection des délais (ce qui est fait lors de l'exécution).

template<typename T> 
T MyClass::GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    throw std::runtime_error("Don't know how to convert " + ToString(v->GetString())); 
} 

Il y a exactement le même sujet/problème discutant de cette chose. S'il vous plaît jeter un oeil à ceci:

Partial template specialization for specific type, c++

+1

mieux que le supprimer est de quitter cela, mais utilisez static_assert (false, "expliquer le problème et la solution"). cela aidera les développeurs à comprendre ce qui ne va pas si l'erreur se produit. –