Dans des projets modérés ou même de grandes projets complexes, la déclaration de modèle et la définition de modèle est utile réduire le temps de compilation.
Cependant, dans un code complexe, de petites erreurs de programmeurs peuvent entraîner un changement de comportement inaperçu, par exemple. Une version générique est appelée au lieu d'une spécialisation. P>
exemple: La spécialisation des modèles est devenue invisible en raison d'une déclaration manquée. P>
///////////////////// file A.hpp ///////////////////// #include <iostream> template <typename T> class A { public: void foo() { std::cerr << " calling generic foo " << std::endl ; } }; // forgetting following declaration leads to an unintended program behaviour template <> void A< int >::foo(); ///////////////////// file A-foo-int.cpp ///////////////////// #include "A.hpp" template <> void A< int >::foo() { std::cerr << "calling <int> version of foo" << std::endl; } ///////////////////// file main.cpp ///////////////////// #include "A.hpp" int main(int argc , char** argv) { A<int>* a = new A<int>(); a->foo(); return 0; } ///////////////////// Makefile ///////////////////// CC = g++ CPPFLAGS += -Wall -O3 CXXFLAGS += --std=gnu++0x all: nonrobust-template-setup nonrobust-template-setup: main.o A-foo-int.o $(CC) $(CPPFLAGS) main.o A-foo-int.o -o nonrobust-template-setup clean: rm -rf *.o nonrobust-template-setup //////////////////////////////////////////
4 Réponses :
Vous ne pouvez pas séparer les déclarations et définitions de cette façon: si vous relégez la définition de vos fonctions de membre spécialisées dans un fichier Normalement, la définition des fonctions des membres d'un modèle de classe se déroule dans un fichier d'en-tête, sauf si em> vous fournissez un instanciation em> pour les modèles de classe correspondants: p> en général, sauf si vous êtes confronté à vraiment em> des problèmes horribles em> horribles délais de compilation horrible, Je vous suggère de suivre la pratique courante et de tout mettre dans un fichier d'en-tête à inclure par toutes les unités de traduction nécessaires à utiliser le modèle de classe: p> si vous êtes face à des problèmes de temps de compilation vraiment horribles, vous pouvez alors séparer les définitions de la fonction membre et les mettre en unités de traduction distinctes. Avec des instanciations explicites, mais en C ++ 11, il n'y a pas de moyen propre / simple pour vous assurer que toutes les spécialisations que vous relégez dans des fichiers distincts Dans certains cas, certaines macros fantaisistes pourraient aider, mais ils apporteraient douteusement plus d'avantages que la douleur à l'entretien dans des projets vraiment complexes. P> Une solution à ce problème a été tentée dans le C ++. 03 Standard en introduisant le mot-clé code> exportation code>, mais l'expérience de la mise en œuvre s'est révélée trop difficile à prendre en charge pour les fournisseurs de compilateur, c'est pourquoi Espérons-le, une meilleure solution pour modules em> va entrer en C ++ 14 et fournir une solution à la conception de modèles. P> P> .cpp code> distinct, peu importe si vous déclarez votre spécialisation immédiatement après le modèle principal, le compilateur ne pourra pas l'installer, et le lien de liaison se plaint des références non résolues.
.cpp code> sont déclarés immédiatement après le modèle principal (comme une bonne pratique recommande ). S'il y avait, je suppose que ce serait si populaire que vous n'auriez pas besoin de venir ici et de demander à ce sujet, car tout le monde em> fait face à un tel problème de conception. P>
exporter code> n'est plus une partie de la norme C ++ (puisque c ++ 11). P>
OK, il semble qu'il n'y ait aucune bonne solution pour ce problème encore disponible, à l'exception des tests d'écriture pour vérifier si une version de méthode correcte est appelée.
@Jarobkroeker: Oui, essentiellement, c'est l'impression que j'ai essayé de transmettre. Je crois qu'il n'y a pas encore de bonne solution pour ce problème.
Je pense que le mieux que vous puissiez faire est de code> static_assert code> que le modèle générique n'est jamais instancié avec les types censés être spécialisés.
Le code suivant est d'illustrer uniquement - je ' d Probablement utiliser boost_static_assert code> (et
std :: is_same code> si je pouvais utiliser c ++ 11). L'idée de base est d'empêcher d'instancier implicitement le modèle non spécialisé avec l'ensemble de types que vous interdisez. Bien sûr, si vous oubliez d'ajouter l'affirmation statique et la spécialisation que vous allez toujours échouer. P>
Si j'ai bien compris la question, l'OP souhaite veiller à ne pas oublier, immédiatement après le modèle principal, de déclarer une spécialisation explicite qu'il définit ultérieurement. Comment un static_assert code> aide dans ce cas?
ok, dans un petit projet, on pourrait probablement faire ce qui suit: Modèle
Le moyen d'être sûr de cela est de ne pas fournir de définition du modèle FOO () code>. Il n'est pas nécessaire de déclarer des spécialisations lorsque vous le faites de cette façon:
// A.cc
#include <cstdio>
#include "A.h"
template<> void A<int>::foo() { puts("foo!"); }
Dans plusieurs cas, une implémentation générique est nécessaire et utile, elle ne peut donc pas être supprimée.
Votre code fourni "Erreur: appelé Generic FOO" pour la mise en œuvre générique m'a amené à croire autrement, il serait peut-être utile de clarifier le libellé de questions pour d'autres
Re: votre code fourni "Erreur: appelé Generic FOO" pour la mise en œuvre générique m'a amené à croire autrement - oui, c'est vrai, désolé pour cela. Peut-être que je devrais éditer l'exemple de code maintenant (si cela est possible)
ok, des commentaires instanciant de la mise en œuvre générique Alors ce que vous voulez Pour trouver des instanciations de gabarit génériques dont les noms de spécialisation en double qui ne devraient avoir été instanciés que dans une liste spécifique des fichiers d'objet compilateur - qui réduit à la recherche de champs de correspondance dans deux jeux de données. Pour cela, il y a EDIT: SED Syntaxe pour les modèles Grep n'a pas vraiment fonctionné très bien. P> p> A
rejoindre code>: p>
Je pense que vous faites tout comme vous le devriez. C'est juste comment ça marche dans c ++ :)