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 :

Fonction template et classe exportée


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Inscrit en
    Août 2006
    Messages
    62
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 62
    Points : 20
    Points
    20
    Par défaut Fonction template et classe exportée
    Bonjour à tous,

    Je rencontre un problème avec les fonctions template de classes exportées. J'ai fais pas mal de recherches mais rien ne correspond à mon cas. Je vous expose le problème :

    Je souhaite exporter une classe (non template) contenant des fonctions template, comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class __declspec(dllexport) MaClasse
    {
    public:
        template <class T> void MaFonction(T Param) { ... }
    };
    Le problème, c'est que les fonctions template ne peuvent pas être exportées.
    Lorsque j'essaie d'utiliser la fonction, j'obtiens cette erreur à la compilation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error LNK2001: unresolved external symbol "__declspec(dllimport) public: class void MaClasse::MaFonction(int)" ...
    J'en conclu que le comilateur (Microsoft Visual C++ 6) cherche la fonction dans la dll.

    Comment peut-on alors spécifier au compilateur de ne pas chercher cette fonction dans la dll, mais de la compiler directement à partir du fichier, sachant qu'elle est forcément inlinée ? Tout en gardant le __declspec(dllexport) devant le nom de la classe.

    J'espère que j'ai été assez clair, si vous voulez plus de précision, n'hésitez pas à me demander.

    Merci d'avance.

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    92
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2005
    Messages : 92
    Points : 108
    Points
    108
    Par défaut
    sachant qu'elle est forcément inlinée
    Il me semble que c'est pas forcé, mais que le compilateur décide. Mais ça change rien au problème.

    Es-tu sûr que tout est bien configuré dans ta compilation? Parce que ça devrait marcher; en tout cas ça marche chez moi dans une situation similaire, avec VC++2005.

    Désolé de pas être plus utile.

  3. #3
    Membre à l'essai
    Inscrit en
    Août 2006
    Messages
    62
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 62
    Points : 20
    Points
    20
    Par défaut
    Merci pour ta réponse Biozic.

    Moi j'ai appris que les fonctions templates doivent forcément être inlinées. Tout du moins, avec MSVC6. Mais je me trompe peut-être, je ne connais pas tout.

    Es-tu sûr que tout est bien configuré dans ta compilation? Parce que ça devrait marcher; en tout cas ça marche chez moi dans une situation similaire, avec VC++2005.
    j'ai pensé également que ça pouvait venir du compilateur, car MSVC6 à pas mal de problèmes avec les templates.
    Qu'est ce que je devrais changer dans les configurations pour pallier à ce problème ? Je ne vois pas trop.

    Merci.

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    92
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2005
    Messages : 92
    Points : 108
    Points
    108
    Par défaut
    Bon, concernant les templates, ils ne sont pas forcément inlinés, puisqu'on a besoin de mettre "inline" devant pour le faire (ou alors le corps de la fonction template est dans la déclaration de la classe, ce qui est ton cas). Mais en plus le compilo est pas obligé de les inliner me semble-t-il.

    Bref, ton problème est peut-être un problème de MSVC6 en effet, parce que sous VC++2005, il n'y a justement rien de spécial à configurer pour que ça marche . A moins que ce soit une erreur bête du genre oublié de linker avec le lib, etc.

  5. #5
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    J'ai cependant une question.

    Si ici la fonction f() n'est pas inline, pourquoi son utilisation dans plusieurs unités de compilation ne provoque pas d'erreur (chez moi) ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <typename T>
    struct Test
    {
      void f();
    };
     
    template <typename T>
    void Test<T>::f() { }
    Il me semble que l'ODR (one-definition rule) n'est pourtant pas respectée.

    J'ai mal fait mon test ?

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    En fait, les fonctions template doivent être inlinées, mais c'est à charge du programmeur que de s'en assurer...

    En effet, si tu vois une fonction template prenant la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    tepmlate <class T>
    T Min(const T& a, const T& b)
    {
        return (a<b ? a:b);
    }
    il manque une information capitale pour pouvoir créer le code machine: le type de donnée utilisé.

    Car, à bien y réfléchir, ce code fonctionnera tout aussi bien pour un char , un short, un int, un réel, voire, meme pour tout type utilisateur ayant définit l'opérateur <...

    Or, le compilateur ne disposera de cette information que... quand il rencontrera l'utilisation de la fonction

    Maintenant, pour ce qui est de savoir ce que le compilateur décidera de faire... ca reste de son seul recours, car il peut tout aussi bien décider, comme pour toute fonction demandée inline par le programmeur, de l'inliner effectivement... ou non...

    Pour completer la réponse, on peut rappeler qu'il y a deux maniières de demander l'inlining d'une fonction au sein d'une classe:
    Soit, on définit la fonction directement au sein de la définition de la classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class LaClass
    {
        public:
            /*...*/
            void laFonction()
            {
                 /* demande implicite d'inliner la fonction */
            }
            /*...*/
    };
    soi on demande explicitement de le faire, mais à ce moment là, la définition de la fonction inlinée doit, au minimum au travers du jeu des inclusion, se retrouver dans le fichier d'en-tête
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class LaClass2
    {
        public:
            /*...*/
            void laFonction();
    };
    inline void LaClass2::laFonction()
    {
        /* inlining explicitement demandé grace au mot clé inline */
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par NiamorH Voir le message
    J'ai cependant une question.

    Si ici la fonction f() n'est pas inline, pourquoi son utilisation dans plusieurs unités de compilation ne provoque pas d'erreur (chez moi) ?

    Il me semble que l'ODR (one-definition rule) n'est pourtant pas respectée.
    Parce que l'ODR est un peu plus complexe que cela. Sa description prend deux pages ou on trouve le paragraphe suivant:
    Citation Envoyé par ISO-19882 3.2/5
    There can be more than one definition of [...] a class template, non static function template, static data member of a class template, member function template or template specialization for which some template parameters are not specified in a program provided that each definition appears in a different translation unit and provided the definitions satisfy the following requirements.[...]
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  8. #8
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par koala01 Voir le message
    En fait, les fonctions template doivent être inlinées, mais c'est à charge du programmeur que de s'en assurer...
    Non. Il y a deux sens a inline:
    - un sens de technique de compilation: le code genere ne comprend pas d'appel de fonction mais le code de celle-ci est place a l'endroit ou il y aurait eu des appels;
    - un sens C++, la definition de la fonction apparait dans la declaration de la classe ou est accompagnee du mot-cle inline. Formellement, ca permet d'avoir plusieurs definitions de la fonction sous certaines conditions. Informellement, ca demande au compilateur d'appliquer le premier sens.

    Les fonctions template ne sont inline ni dans un sens ni dans l'autre. (Edit: Mais un compilateur peut rendre n'importe quelle fonction, y compris template, inline dans le premier sens s'il le veut).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  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
    Points : 1 051
    Points
    1 051
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Parce que l'ODR est un peu plus complexe que cela. Sa description prend deux pages ou on trouve le paragraphe suivant:
    Ok merci pour la précision.

    Non. Il y a deux sens a inline:
    - un sens de technique de compilation: le code genere ne comprend pas d'appel de fonction mais le code de celle-ci est place a l'endroit ou il y aurait eu des appels;
    - un sens C++, la definition de la fonction apparait dans la définition de la classe ou est accompagnee du mot-cle inline. Formellement, ca permet d'avoir plusieurs definitions de la fonction sous certaines conditions. Informellement, ca demande au compilateur d'appliquer le premier sens.
    Ok.

    Les fonctions template ne sont inline ni dans un sens ni dans l'autre.
    Quoi ? De base tu veux dire (sans spécifier le mot clef inline) ? Sinon je comprends plus rien.

  10. #10
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par NiamorH Voir le message
    De base tu veux dire (sans spécifier le mot clef inline) ? Sinon je comprends plus rien.
    Oui. Sinon naturellement elle le sont dans le second. Et aussi, le compilateur peut inliner tout ce qu'il veut sans qu'on lui demande et le fait que la definition soit accessible aide le compilateur a le faire (c'est une des raisons pour lesquelles le inline du C++ permet d'avoir plusieurs definitions).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  11. #11
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Question stupide mais essentiel à mes yeux.

    Comment peut ton créer une DLL de fonction template ?

    Ceci me parait un non sens puisque par définition les templates sont intimement lié à la phase de compilation alors qu'au contraire, les DLL sont faites pour être chargé dynamiquement lors de l'exécution.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Davidbrcz Voir le message
    Question stupide mais essentiel à mes yeux.
    Comment peut ton crée une DLL d e fonction template ?
    Non (du moins en C++, dans d'autres langages ayant d'autres contraintes -- en particulier pas de specialisation explicite -- c'est envisageable/possible) . Tu peux mettre des instantiations dans une DLL.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  13. #13
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Merci.
    C'est bien ce que je pensais.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  14. #14
    Membre à l'essai
    Inscrit en
    Août 2006
    Messages
    62
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 62
    Points : 20
    Points
    20
    Par défaut
    Merci pour toutes vos réponses.

    Si ici la fonction f() n'est pas inline, pourquoi son utilisation dans plusieurs unités de compilation ne provoque pas d'erreur (chez moi) ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <typename T>
    struct Test
    {
      void f();
    };
     
    template <typename T>
    void Test<T>::f() { }
    Dans ce cas, c'est la structure qui est template et non la fonction f(), donc il n'y a pas de problème.

    Question stupide mais essentiel à mes yeux.
    Comment peut ton créer une DLL de fonction template ?
    Justement, on ne peux pas, comme l'a précisé Jean-Marc.Bourguet. La seule chose que l'on peux faire est de créer des spécialisations avec différents types, comme ceci par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <class T>
    class c {};
     
    typedef c<int> ci;
    ...
    Dans mon cas, ce n'est pas un problème d'inlining, mais d'exportation/importation. Je met mes fonctions template inline, justement parce qu'on ne peux pas les inclure dans la dll. Le compilateur devra alors compiler ces fonctions avec les types utilisés par le programmeur.

    Le compilateur pense qu'il doit aller chercher le code de la fonction dans la dll :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error LNK2001: unresolved external symbol "__declspec(dllimport) public: class void MaClasse::MaFonction(int)" ...
    Alors que la fonction est non seulement template mais inline.

    Voila, j'espère que je ne vous ai pas embrouillés

  15. #15
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    Citation Envoyé par xwindoo Voir le message
    La seule chose que l'on peux faire est de créer des spécialisations avec différents types, comme ceci par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <class T>
    class c {};
     
    typedef c<int> ci;
    ...
    Un typedef ne crée aucune instance du template.

  16. #16
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Non. Il y a deux sens a inline:
    - [...]
    - un sens C++, la definition de la fonction apparait dans la declaration de la classe ou est accompagnee du mot-cle inline. Formellement, ca permet d'avoir plusieurs definitions de la fonction sous certaines conditions.
    Tu aurais un exemple pour le coup de "plusieurs définitions" s'il te plaît ?

  17. #17
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    typiquement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // unit1.cpp
     
    inline
    int func()
    {
      return 3;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // unit2.cpp
     
    inline
    int func()
    {
      return 3;
    }
    devrait compiler

  18. #18
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Mais on peut donc modifier le corps de func sans que le compilo ne se doute de rien ?
    Et toutes les fonctions et classes qui utilisent func dans l'une de ces unités de compilation va se servir de la func qui y est définie ?

  19. #19
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    Si tu modifies leur corps, ca devient un comportement indéfini. (d'après C++ templates the complete guide)

    Il appellent ça : la "Cross-Translation Unit Equivalence Constraints"

  20. #20
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    J'irai voir. Merci pour l'info.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Fonction template et classe virtuelle
    Par Trademark dans le forum Langage
    Réponses: 5
    Dernier message: 25/11/2011, 19h30
  2. Syntaxe fonction template dans classe template
    Par Aleph69 dans le forum C++
    Réponses: 6
    Dernier message: 15/07/2011, 15h32
  3. Réponses: 4
    Dernier message: 15/10/2008, 09h33
  4. Réponses: 3
    Dernier message: 08/07/2008, 15h06
  5. Problèmes de fonctions membres de classe templates, gcc3.3.6
    Par yves.dessertine dans le forum Autres éditeurs
    Réponses: 12
    Dernier message: 17/10/2005, 21h36

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