2008-09-12 6 views
25

Supposons que j'ai fileA.h qui déclare une classe classA avec la fonction de modèle SomeFunc<T>(). Cette fonction est implémentée directement dans le fichier d'en-tête (comme d'habitude pour les fonctions de template). Maintenant, j'ajoute une implémentation spécialisée de SomeFunc() (comme pour SomeFunc<int>()) dans fileA.C (c'est-à-dire pas dans le fichier d'en-tête).Visibilité de la spécialisation de modèle de la fonction C++

Si j'appelle maintenant SomeFunc<int>() d'un autre code (peut-être aussi d'une autre bibliothèque), appellerait-il la version générique, ou la spécialisation?

J'ai ce problème en ce moment, où la classe et la fonction vivent dans une bibliothèque qui est utilisée par deux applications. Et une application utilise correctement la spécialisation, tandis qu'une autre application utilise le formulaire générique (ce qui provoque des problèmes d'exécution plus tard). Pourquoi la différence? Cela peut-il être lié aux options de l'éditeur de liens, etc.? C'est sur Linux, avec g ++ 4.1.2.

Répondre

0

À moins que la fonction de modèle spécialisé ne figure également dans le fichier d'en-tête, l'autre application n'aura aucune connaissance de la version spécialisée. La solution est d'ajouter SomeFunc<int>() à l'en-tête.

9

Avez-vous ajouté un prototype avec des paramètres à votre fichier d'en-tête?

Je veux dire est là quelque part dans fileA.h

template<> SomeFunc<int>(); 

Sinon c'est probablement la raison.

0

Brandon: c'est ce que je pensais - la fonction spécialisée ne devrait jamais être appelée. Ce qui est vrai pour la deuxième application que j'ai mentionnée. La première application, cependant, appelle clairement la forme spécialisée même si la spécialisation n'est pas déclarée dans le fichier d'en-tête!

Je cherche surtout l'illumination ici :-) parce que la première application est un test unitaire, et il est regrettable d'avoir un bug qui ne figure pas dans le test, mais dans l'application réelle ...

(PS : J'ai corrigé ce bug spécifique, en déclarant la spécialisation dans l'en-tête, mais quels autres bogues similaires pourraient encore être cachés?)

2

Selon les spécifications, votre modèle de fonction spécialisé ne doit jamais être appelé en dehors de fileA.C, sauf si vous export la définition du modèle, qu'aucun compilateur (sauf Comeau) ne supporte actuellement (ou a prévu pour l'avenir prévisible). En revanche, une fois le modèle de fonction instancié, il existe une fonction visible pour le compilateur qui n'est plus un modèle. GCC peut réutiliser cette définition entre différentes unités de compilation car la norme stipule que chaque modèle ne doit être instancié qu'une seule fois pour un ensemble donné d'arguments de type [temp.spec]. Cependant, puisque le modèle n'est pas exporté, ceci devrait être limité à l'unité de compilation.

Je crois que GCC peut exposer un bogue ici en partageant sa liste de modèles instanciés à travers les unités de compilation. Normalement, il s'agit d'une optimisation raisonnable, mais il faut tenir compte des spécialisations fonctionnelles qui ne semblent pas fonctionner correctement.

0

Dans Microsoft C++, j'ai fait une expérience avec des fonctions en ligne. Je voulais savoir ce qui se passerait si je définissais des versions incompatibles d'une fonction dans différentes sources. J'ai obtenu des résultats différents selon que j'utilisais une version Debug ou une version Release. Dans le débogage, le compilateur refuse de mettre en ligne quoi que ce soit et l'éditeur de liens reliait la même version de la fonction, quelle que soit la portée de la source.Dans Release, le compilateur est inséré quelle que soit la version définie à ce moment, et vous avez différentes versions de la fonction.

Dans les deux cas, aucun avertissement n'a été émis. Je m'en doutais, c'est pourquoi j'ai fait l'expérience. Je suppose que les fonctions du modèle se comporteraient de la même manière que les autres compilateurs.

22

Il est une erreur d'avoir une spécialisation pour un modèle non visible au moment de l'appel. Malheureusement, les compilateurs ne sont pas tenus de diagnostiquer cette erreur, et peuvent ensuite faire ce qu'ils veulent avec votre code (en standard, il est "mal formé, aucun diagnostic requis").

Techniquement, vous devez définir la spécialisation dans le fichier d'en-tête, mais à peu près tous compilateur va gérer ce que vous pourriez attendre: il est fixé en C++ 11 avec la nouvelle installation « template extern »:

extern template<> SomeFunc<int>(); 

Ceci indique explicitement que la spécialisation particulière est définie ailleurs. De nombreux compilateurs le supportent déjà, certains avec et d'autres sans le extern.

0

@ [anthony-williams],

êtes-vous que vous n'êtes pas confondre extern déclarations de modèle avec extern template instanciations? De ce que je vois, extern template peut seulement être utilisé pour l'instanciation explicite, pas pour la spécialisation (ce qui implique l'instanciation implicite). [Temp.expl.spec] ne mentionne pas le mot-clé extern:

explicite-spécialisation:
        template <>déclaration

+0

Zut, la liaison automatique du nom d'utilisateur ne fonctionne pas. –

3

J'ai eu le même problème avec gcc4, voici comment je l'ai résolu. C'était une solution plus simple que ce à quoi je m'étais laissé croire par les commentaires précédents. Les idées de posts précédents étaient correctes mais leur syntaxe ne fonctionnait pas pour moi.


    ----------header----------------- 
    template < class A > 
    void foobar(A& object) 
    { 
     std::cout << object; 
    } 

    template <> 
    void foobar(int); 

    ---------source------------------ 
    #include "header.hpp" 

    template <> 
    void foobar(int x) 
    { 
     std::cout << "an int"; 
    } 

+0

SOB qui a été formaté dans l'aperçu! Pardon –

1

Comme le dit Anthony Williams, la construction extern template est la bonne façon de le faire, mais depuis son exemple de code est incomplet et a de multiples erreurs de syntaxe, voici une solution complète.

fileA.h:

namespace myNamespace { 
    class classA { 
    public: 
     template <class T> void SomeFunc() { ... } 
    }; 

    // The following line declares the specialization SomeFunc<int>(). 
    template <> void classA::SomeFunc<int>(); 

    // The following line externalizes the instantiation of the previously 
    // declared specialization SomeFunc<int>(). If the preceding line is omitted, 
    // the following line PREVENTS the specialization of SomeFunc<int>(); 
    // SomeFunc<int>() will not be usable unless it is manually instantiated 
    // separately). When the preceding line is included, all the compilers I 
    // tested this on, including gcc, behave exactly the same (throwing a link 
    // error if the specialization of SomeFunc<int>() is not instantiated 
    // separately), regardless of whether or not the following line is included; 
    // however, my understanding is that nothing in the standard requires that 
    // behavior if the following line is NOT included. 
    extern template void classA::SomeFunc<int>(); 
} 

fileA.C:

#include "fileA.h" 

template <> void myNamespace::classA::SomeFunc<int>() { ... } 
Questions connexes