2009-11-12 4 views
60

considérant toujours que l'en-tête suivant, contenant ma classe basé sur un modèle, est inclus dans au moins deux fichiers .CPP, ce code compile correctement:spécialisation de modèle d'une seule méthode d'une classe basé sur un modèle

template <class T> 
class TClass 
{ 
public: 
void doSomething(std::vector<T> * v); 
}; 

template <class T> 
void TClass<T>::doSomething(std::vector<T> * v) { 
// Do somtehing with a vector of a generic T 
} 

template <> 
inline void TClass<int>::doSomething(std::vector<int> * v) { 
// Do somtehing with a vector of int's 
} 

Mais notez la ligne dans la méthode de spécialisation. Il est nécessaire que le code ne comporte pas d'erreur de liaison (dans VS2008 est LNK2005) car la méthode est définie plus d'une fois. Je comprends cela car AFAIK une spécialisation de modèle complet est la même chose qu'une définition de méthode simple.

Alors, comment puis-je supprimer ce inline? Le code ne doit pas être dupliqué à chaque utilisation. J'ai cherché Google, lu quelques questions ici dans SO et essayé beaucoup de solutions suggérées mais aucun n'a été construit avec succès (du moins pas dans VS 2008).

Merci!

+3

Pourquoi voulez-vous supprimer l'inline? Trouvez-vous cela esthétiquement déplaisant? Pensez-vous que cela change la signification de votre code? –

+0

Parce que si cette méthode devait être "longue" et utilisée dans beaucoup d'endroits, j'obtiendrais son code binaire copié partout, n'est-ce pas? J'ai essayé d'expliquer ceci dans la question mais je suppose que ce n'était pas clair ... :) – Chuim

+0

@Martin: Que faire si l'implémentation a besoin de beaucoup d'autre code qui doit alors être inclus par cet entête au lieu du fichier cpp? – sbi

Répondre

50

Comme pour les fonctions simples, vous pouvez utiliser la déclaration et l'implémentation. Mettez dans votre déclaration d'en-tête:

template <> 
void TClass<int>::doSomething(std::vector<int> * v); 

et mettre la mise en œuvre dans l'un de vos fichiers cpp-:

template <> 
void TClass<int>::doSomething(std::vector<int> * v) { 
// Do somtehing with a vector of int's 
} 

Ne pas oublier de retirer en ligne (j'ai oublié et je pensais que cette solution ne fonctionnera pas:)). Vérifié sur VC++ 2005

+0

J'ai essayé quelque chose au moins semblable à cela avant, mais j'ai eu d'autres erreurs mais maintenant que vous avez mentionné que j'ai dû oublier de supprimer le 'inline' tout en copiant/collant. De cette façon, cela a fonctionné! – Chuim

+0

La même chose s'applique aux fonctions libres de modèle (par opposition aux méthodes de classe). Je recevais la même erreur de lien pour ma spécialisation de fonction. J'ai déplacé le corps de la spécialisation de la fonction dans un fichier .cpp et laissé la déclaration de la spécialisation dans l'en-tête, et tout a fonctionné. Merci! – aldo

+0

Je viens de rencontrer ce problème, et ce qui précède l'a résolu pour moi. En outre, vous devez prendre soin de l'endroit où le compilateur * développe * le code du modèle. Si c'est fait deux fois, le compilateur se plaignent de plusieurs définitions. – Diederik

3

Vous devez déplacer la définition de spécialisation vers le fichier CPP. La spécialisation de la fonction membre de la classe modèle est autorisée même si la fonction n'est pas déclarée comme modèle.

+0

C'était la direction que je connaissais déjà. Mais je cherchais la réponse finale parce que je ne comprenais pas bien. – Chuim

1

Il n'y a aucune raison de supprimer le mot-clé en ligne.
Cela ne change en rien la signification du code.

+0

Copié à partir du commentaire de question: Parce que si cette méthode serait "longue" et utilisée dans beaucoup d'endroits j'obtiendrais son code binaire copié partout, non? J'ai essayé d'expliquer cela dans la question mais je suppose que ce n'était pas clair ... :) – Chuim

+0

Non. L'éditeur de liens supprime toutes les copies supplémentaires. Donc, dans une application ou lib vous n'auriez qu'une seule instance de la méthode. –

+3

Si le mot-clé 'inline' aboutit à ce que la fonction soit réellement incorporée (la norme dit que le compilateur devrait le considérer comme un indice), ces copies supplémentaires ne peuvent pas être supprimées. Il ne s'agit cependant que d'un indice (son principal effet est de ne pas générer d'erreurs sur les collisions de liens d'une manière particulière). – Yakk

0

Si vous voulez supprimer l'inline pour une raison quelconque, la solution de maxim1000 est parfaitement valide.

Dans votre commentaire, cependant, il semble que vous croyez que le mot-clé inline signifie que la fonction avec tout son contenu est toujours inline mais AFAIK qui est en fait très dépendante de l'optimisation de votre compilateur.

Je cite la C++ FAQ

Il existe plusieurs façons de désigner qu'une fonction est en ligne, certains d'entre qui impliquent le mot-clé en ligne, d'autres ne le font pas. Peu importe comment vous désigner une fonction comme en ligne, il est une demande que le compilateur est autorisé à ignorer: le compilateur peut développer en ligne une partie, tous ou aucun des endroits où vous appelez une fonction désignée comme inline. (Ne pas se décourager si cela semble désespérément vague.La flexibilité du ci-dessus est en fait un énorme avantage: il permet au compilateur de traiter les grandes fonctions différemment des petites, plus il permet au compilateur de générer du code qui est facile à déboguer si vous sélectionnez les bonnes options du compilateur.)

Donc, à moins que vous savez que cette fonction sera effectivement météorisation votre exécutable ou si vous voulez le retirer de l'en-tête de définition de modèle pour d'autres raisons, vous pouvez réellement le laisser où il est sans aucun dommage

Questions connexes