En considérant toujours que l'en-tête suivant, contenant ma classe basée sur un modèle, est inclus dans au moins deux .CPP
fichiers, ce code se compile correctement:
template <class T>
class TClass
{
public:
void doSomething(std::vector<T> * v);
};
template <class T>
void TClass<T>::doSomething(std::vector<T> * v) {
// Do something with a vector of a generic T
}
template <>
inline void TClass<int>::doSomething(std::vector<int> * v) {
// Do something with a vector of int's
}
Mais notez l'inline dans la méthode de spécialisation. Il est nécessaire d'éviter une erreur de l'éditeur de liens (dans VS2008 est LNK2005) car la méthode est définie plus d'une fois. Je comprends cela car AFAIK une spécialisation complète de modèle est la même qu'une simple définition de méthode.
Alors, comment puis-je supprimer cela inline
? Le code ne doit pas être dupliqué à chaque utilisation. J'ai cherché sur Google, lu quelques questions ici dans SO et essayé plusieurs des solutions suggérées, mais aucune n'a été construite avec succès (du moins pas dans VS 2008).
Merci!
Réponses:
Comme pour les fonctions simples, vous pouvez utiliser la déclaration et l'implémentation. Mettez dans votre déclaration d'en-tête:
et mettez l'implémentation dans l'un de vos fichiers cpp:
N'oubliez pas de supprimer inline (j'ai oublié et j'ai pensé que cette solution ne fonctionnera pas :)). Vérifié sur VC ++ 2005
la source
inline
copier / coller while. De cette façon, cela a fonctionné!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.
la source
Il n'y a aucune raison de supprimer le mot-clé en ligne.
Cela ne change en rien la signification du code.
la source
inline
mot - clé aboutit à ce que la fonction soit réellement insérée (le standard dit que le compilateur doit le prendre comme un indice), alors ces copies supplémentaires ne peuvent pas être supprimées. Ce n'est, cependant, qu'un indice pour en ligne (son effet principal est de dire "ne pas générer d'erreurs sur les collisions de liens d'une manière particulière")Si vous souhaitez supprimer l'inline pour une raison quelconque, la solution de maxim1000 est parfaitement valable.
Dans votre commentaire, cependant, il semble que vous pensiez que le mot-clé inline signifie que la fonction avec tout son contenu est toujours intégrée, mais AFAIK qui dépend en fait beaucoup de l'optimisation de votre compilateur.
Citations de la FAQ C ++
Donc, à moins que vous ne sachiez que cette fonction gonflera réellement votre exécutable ou à moins que vous ne vouliez le supprimer de l'en-tête de définition du modèle pour d'autres raisons, vous pouvez réellement le laisser là où il se trouve sans aucun dommage.
la source
Je voudrais ajouter qu'il y a toujours une bonne raison de conserver le
inline
mot - clé si vous avez l'intention de laisser également la spécialisation dans le fichier d'en-tête.Référence: https://stackoverflow.com/a/4445772/1294184
la source
C'est un peu OT, mais j'ai pensé laisser ça ici au cas où cela aiderait quelqu'un d'autre. Je cherchais sur la spécialisation des modèles sur Google, ce qui m'a conduit ici, et bien que la réponse de @ maxim1000 soit correcte et m'a finalement aidé à résoudre mes problèmes, je ne pensais pas que c'était très clair.
Ma situation est un peu différente (mais assez similaire pour laisser cette réponse je pense) que celle de l'OP. Fondamentalement, j'utilise une bibliothèque tierce avec toutes sortes de classes qui définissent des "types d'état". Le cœur de ces types est simplement
enum
s, mais les classes héritent toutes d'un parent commun (abstrait) et fournissent différentes fonctions d'utilité, telles que la surcharge d'opérateurs et unestatic toString(enum type)
fonction. Chaque statutenum
est différent les uns des autres et sans rapport. Par exemple, l'unenum
a les champsNORMAL, DEGRADED, INOPERABLE
, un autre aAVAILBLE, PENDING, MISSING
, etc. Mon logiciel est en charge de gérer différents types de statuts pour différents composants. Il est arrivé que je voulais utiliser lestoString
fonctions pour cesenum
classes, mais comme elles sont abstraites, je ne peux pas les instancier directement. J'aurais pu étendre chaque classe que je voulais utiliser, mais j'ai finalement décidé de créer unetemplate
classe, où letypename
serait le statut concret qui me tenait àenum
cœur. Probablement un débat peut avoir lieu à propos de cette décision, mais j'ai senti que c'était beaucoup moins de travail que d'étendre chaqueenum
classe abstraite avec une classe personnalisée et d'implémenter les fonctions abstraites. Et bien sûr, dans mon code, je voulais juste pouvoir appeler.toString(enum type)
et lui faire imprimer la représentation sous forme de chaîne de celaenum
. Puisque tous lesenum
s étaient totalement sans rapport, ils avaient chacun leur propretoString
fonctions qui (après quelques recherches que j'ai apprises) ont dû être appelées en utilisant la spécialisation des modèles. Cela m'a conduit ici. Vous trouverez ci-dessous un MCVE de ce que je devais faire pour que cela fonctionne correctement. Et en fait, ma solution était un peu différente de celle de @ maxim1000.Il s'agit d'un fichier d'en-tête (grandement simplifié) pour le
enum
s. En réalité, chaqueenum
classe était définie dans son propre fichier. Ce fichier représente les fichiers d'en-tête qui me sont fournis dans le cadre de la bibliothèque que j'utilise:en ajoutant cette ligne juste pour séparer le fichier suivant dans un bloc de code différent:
fichier suivant
fichier suivant
et cela produit:
Je ne sais pas si c'est la solution idéale pour résoudre mon problème, mais cela a fonctionné pour moi. Maintenant, quel que soit le nombre de types d'énumérations que je
toString
finis par utiliser, tout ce que j'ai à faire est d'ajouter quelques lignes pour la méthode dans le fichier .cpp, et je peux utiliser latoString
méthode déjà définie des bibliothèques sans l'implémenter moi-même et sans étendre chacuneenum
classe que je veux utiliser.la source