IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

template et __declspec(dllexport)


Sujet :

Langage C++

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 825
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 825
    Par défaut template et __declspec(dllexport)
    Bonjour à tous,

    Dans ma DLL, je rajoute une classe avec un template:

    MaClass.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template <class T>
    class __declspec(dllexport) MaClass
    {
    public:
        CMaClass();
    }
    Puis l'implémentation (MaClass.cpp) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #include "CMaClass.h"
     
    template<class T>
    CMaClass<T>::CMaClass()
    {
     
    }
    Pour que ça soit compilé dans ma DLL avec un type particulier, je rajoute tout à la fin du .h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    typedef CMaClass<float> TFloatMaClass;
    Lors que j'utilise cette classe, j'ai des erreurs de link :'( comme si elle n'avait pas été compilé malgrès le typedef.


    Que faut-il que je fasse?

    Merci beaucoup,

    A bientôt

  2. #2
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    Bonjour,

    Les classes templates ne sont que des patrons de classe. L'instanciation réelle d'un template à lieu à la compilation du *fichier qui l'utilise*.

    Ainsi dans un un fichier qui utilise des templates, le compilateur doit avoir accès au code source de ce template, et non pas seulement sa déclaration.

    Donc cela n'a aucun sens de mettre une classe template en export d'une DLL.

    La solution consiste à mettre en export d'une DLL des classes templates instanciés sur un type réel. Or comme on ne peut exporter un typedef, on doit passer par un simple héritage.

    Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    template<typename T>
    class TplClass {
    ...
    };
     
    __declspec(export) class TFloatClass : public TplClass<float> {
    };
     
    __declspec(export) class TIntClass : public TplClass<int> {
    };
    ...

  3. #3
    Membre confirmé Avatar de babar63
    Homme Profil pro
    Développeur jeux vidéos/3d Temps réel
    Inscrit en
    Septembre 2005
    Messages
    241
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Développeur jeux vidéos/3d Temps réel

    Informations forums :
    Inscription : Septembre 2005
    Messages : 241
    Par défaut
    Citation Envoyé par mchk0123 Voir le message
    Bonjour,

    Les classes templates ne sont que des patrons de classe. L'instanciation réelle d'un template à lieu à la compilation du *fichier qui l'utilise*.

    Ainsi dans un un fichier qui utilise des templates, le compilateur doit avoir accès au code source de ce template, et non pas seulement sa déclaration.

    Donc cela n'a aucun sens de mettre une classe template en export d'une DLL.

    La solution consiste à mettre en export d'une DLL des classes templates instanciés sur un type réel. Or comme on ne peut exporter un typedef, on doit passer par un simple héritage.

    Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    template<typename T>
    class TplClass {
    ...
    };
     
    __declspec(export) class TFloatClass : public TplClass<float> {
    };
     
    __declspec(export) class TIntClass : public TplClass<int> {
    };
    ...
    Quelle est l'intérêt de faire ça? J'avoue que je ne vois pas (), pour ma part j'aurais plutôt fais ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    // fichier MaClassTpl.h :
     
    template<typename T>
    class CMaClassTpl
    {
           // Implémentation ?
    };
    #include "MaClassTpl.inl"         // Si on souhaite séparer l'implémentation
     
     
    typedef CMaClassTpl<float> TFloatMaClass;
    //...

  4. #4
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par mchk0123 Voir le message
    La solution consiste à mettre en export d'une DLL des classes templates instanciés sur un type réel. Or comme on ne peut exporter un typedef, on doit passer par un simple héritage.
    La vraie solution consiste à instancier explicitement via le mot clef "template", dans un cpp créé pour l'occasion.

    Une recherche sur les mots clefs instanciation explicite pourait aider.

  5. #5
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    Citation Envoyé par NiamorH Voir le message
    La vraie solution consiste à instancier explicitement via le mot clef "template", dans un cpp créé pour l'occasion.

    Une recherche sur les mots clefs instanciation explicite pourait aider.
    C'est exactement la solution proposée par babar63 mais elle ne permet pas son référencement de la section export d'un DLL.

    Citation Envoyé par babr63
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    template<typename T>
    class TplClass {
    ...
    };
     
    __declspec(export) class TFloatClass : public TplClass<float> {
    };
     
    __declspec(export) class TIntClass : public TplClass<int> {
    };
    ...
    Quelle est l'intérêt de faire ça? J'avoue que je ne vois pas (), pour ma part j'aurais plutôt fais ça
    Réponse : il y en a plusieurs, et tous son relié au fait qu'un export dans une DLL permet de masquer l'implémentation de la classe à son utilisateur (seul le fichier ma_dll.h est fourni). En vrac, voilà plusieurs raisons :

    1. protection du code souce (éviter de casser l'encapsulation), cela évite qu'un bidouilleur s'amuse à mettre les mains dedans
    2. clareté du code livré. Utiliser une bibliothèque comportant une DLL + fichier .h est un vrai bonheur, à contrario de pas mal de bibliothèques qui font un usage à outrance des templates.
    3. rapidité d'intégration d'une bibliothèque (pas besoin de recompiler la totalité des fichiers templates). Il n'y a rien de plus agacant que d'avoir à recompiler à chaque fois une bibliothèque sur chacun de nos projets. J'ai déjà vu des bibliothèques ou le nombre de classes templates >> 100 ! Je ne vous dit pas les temps de compilation.
    4. garder son savoir faire (livraison dans un cadre professionel ou commercial)
    5. Et *le tout* sans avoir à ré-implémenter N x la même classe pour chaque type concret différent.

    Bref, la solution que je propose (qui est d'un usage trés trés courant) offre le meilleur de 2 mondes : DLL + templates. C'est d'ailleurs le titre du sujet.

  6. #6
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par mchk0123 Voir le message
    C'est exactement la solution proposée par babar63 mais elle ne permet pas son référencement de la section export d'un DLL.
    J'ai beau relire...

    Attention, je parle du mot clef template et non pas typedef qui lui n'instancie rien du tout.

    Rajoute dans un .cpp à part qui lui même inclut le CPP (non je me suis pas trompé d'extention, pas besoin d'INL) de ton template et tu auras tout les avantages cités plus hauts, sans passer par un quelquonque héritage.

  7. #7
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    D'ailleurs l'initiateur de ce sujet est le même que la derniere fois qu'on en a parlé. http://www.developpez.net/forums/sho...tion+explicite

    Il exagère!

  8. #8
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    Le sujet du post est de pouvoir exporter une classe template au sein d'une DLL.
    Ce qui est trés difficile voir infaisable sans passer par un héritage simple.

    Est-ce que l'on peut faire quelque chose comme ? :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    __declspec(dllexport) template MyClass<MonType>;
    J'en doute.

  9. #9
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par mister3957 Voir le message
    Lors que j'utilise cette classe, j'ai des erreurs de link :'( comme si elle n'avait pas été compilé malgrès le typedef.
    Tout à l'air de s'être bien passé pourtant. Il ne manque l'instance du template.

    Donc déjà il peut essayer et nous dire.

    Je ne pense pas qu'il faille mettre le export devant l'instanciation explicite mais devant la définition de la classe comme toute autre classe.

  10. #10
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    En faisant un test rapide :

    Code Test.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    #ifndef TestH
    #define TestH
     
    template<typename T>
    class __declspec(dllexport) MyClass {
      public:
        MyClass();
        MyClass(const T &x);
        T mult(const T &y);
      protected:
        T x;
    };
     
    #include "test.cpp"
     
    template class MyClass<float>;
    template class MyClass<int>;
     
    #endif // !TestH
    Code Test.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    #include "test.h"
     
    template<typename T>
    MyClass<T>::MyClass() : x(0) {
    }
     
    template<typename T>
    MyClass<T>::MyClass(const T &x) : x(x) {
    }
     
    template<typename T>
    T MyClass<T>::mult(const T &y) {
      T i, ret;
     
      ret = x;
      for (i = 0; i < y; i++)
        ret += x;
     
      return ret;
    }

    Effectivement cela compile, mais il n'y a absolument rien d'exporté dans la DLL.

  11. #11
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Gloups malheureux, les directives d'instanciation ne sont pas à mettre dans des .h, ça risque de te jouer des tours si deux cpp utilisent ce même .h. J'ai donné la bonne utilisation : dans un cpp a part, qui inclut le cpp du template.

    Après ça ne marche peut-être pas, mais ça m'étonnerait vraiment.

  12. #12
    Membre éprouvé
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 825
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 825
    Par défaut
    Le typedef ne fait pas d'instanciation explicite.

    Il faut ajouter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    template MyClass<int>;
    template MyClass<float>;
    //etc...
    Mais lorsqu'on fait ça, on a plein de warning (4661 si je me souvient bien) indiquant que les méthode spécifiques à ces instanciations explicites ne sont pas implémentées.

    Donc j'ai fait un fichier .inl que j'inclu dans le .h afin que le code soit compilé non pas dans la DLL, mais dans le projet appelant.

    Je voulais quand même éviter au projet appelant d'avoir à les compiler pour gagner en temps de compilation mais bon, ça ira bien comme ça.


    Merci beaucoup

  13. #13
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    Mes excuses Niamorh, tu as raison ; après correction de l'exemple que j'ai donné il y a bien des symboles exportés.

    C'est vraiment une super astuce ... A réutiliser sans modération !
    C'est parfait pour la livraison de code source compilé !!!!

    Une dernière question : y a t'il des doublons dans les symboles quand on livre également l'implémentation des templates en plus de la DLL ? Par exemple si on veut livrer du code pré-compilé ET permettre une extension de type sur le template :

    Code ProgrammePrincipal.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #include "MaClass.h"
     
    typedef MaClass<MonType> TMonType;
     
    int main() {
      TMonType o1;
      MaClass<float> o2;
     
      return 0;
    }

    Pour l'objet o1, il n'y a pas de soucis ; mais pour l'objet o2 que fait le compilateur ? Il prend l'instanciation dans la DLL ? Il ignore l'instanciation dans le main ?

  14. #14
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Je ne suis pas certain de comprendre correctement ta question, ou même le but :

    - tu fournis a ton client un .h et un .inl avec une implémentation. MaClasse<T>
    - tu fournis aussi une dll comprennant une instance d'une spécialisation complète du template pour un type. MaClasse<Special>

    C'est ça ?

  15. #15
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    Oui c'est ça, mais je penses avoir la réponse.

    J'ajoutait systématiquement un #include "MaClasse.inc" à la fin de "MaClasse.h", pour que le compilateur ait toujours connaissance de l'implémentation du template.

    Mais à la réflexion je penses que la bonne méthode, c'est d'inclure le fichier ".inc" seulement là où c'est nécéssaire.

    Je ferme cette parenthèse.

    Pour mister3957, je rectifie ce que j'avais dit (merci beaucoup NiamorH) :

    1. Tu peut trés bien pré-compiler ta classe template MaClass en la spécialisant sur quelques types les plus utilisés. Dans un fichier ".cpp" à part , tu fait par exemple "template MaClass<float>;"

    2. Ensuite tout dépend si tu ces quelques spécialisations sont suffisantes. Ou si tu veux aussi permettre d'autres spécialisations en dehors de la DLL ?

  16. #16
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par mister3957 Voir le message
    Mais lorsqu'on fait ça, on a plein de warning (4661 si je me souvient bien) indiquant que les méthode spécifiques à ces instanciations explicites ne sont pas implémentées.
    Quand tu dis "ajouter", c'est dans le .h ? Ou avec la méthode que j'ai décrite plus haut ? C'est bizare car l'instanciation explicite marche depuis VC6 et tu sembles utiliser un compilateur de microsoft non ?

    les méthode spécifiques à ces instanciations explicites
    Tu parles de spécialisations de template pour ces types ? Ou des méthodes du primary template ?

    Dans les deux cas, à l'endroit où tu fais une instanciation explicite, toutes les méthodes (spécialisées ou non) doivent évidement être visibles. C'est pour ça qu'on inclut le .cpp et non pas seulement le .h

Discussions similaires

  1. __declspec(dllexport) et membres
    Par mister3957 dans le forum C++
    Réponses: 6
    Dernier message: 25/03/2009, 14h26
  2. Réponses: 11
    Dernier message: 06/11/2008, 09h49
  3. static et __declspec(dllexport)
    Par squale69 dans le forum Visual C++
    Réponses: 2
    Dernier message: 16/05/2008, 00h01
  4. template et __declspec(dllexport) : LNK2019
    Par mister3957 dans le forum Langage
    Réponses: 14
    Dernier message: 04/01/2008, 10h43
  5. __declspec(dllexport) dans mon fichier header mais...?
    Par Jasmine dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 03/03/2004, 18h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo