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 :

Spécialisation de template


Sujet :

Langage C++

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Octobre 2014
    Messages : 6
    Points : 5
    Points
    5
    Par défaut Spécialisation de template
    Bonjour à tous,
    J'aimerais savoir s'il était possible de créer l'architecture suivante:
    • Une classe mère abstraite et template A. Son type générique doit absolument hériter T.
    • Une classe abstraite T.
    • Des classe t, qui héritent chacune de T.
    • Des classes F. Chacune d'entre elle est une spécialisation, non pas de A, mais pour un certain t, de A<t>. Donc F est une implémentation de A pour un seul t.

    J'ai déjà essayé mais cela n'a pas été concluant... En effet, il doit y avoir un problème avec l'utilisation à la fois de polymorphisme statique (template) et dynamique(A est abstraite).
    Merci d'avance pour vos réponse!

  2. #2
    Invité
    Invité(e)
    Par défaut
    salut,

    ben si A<T> est abstraite, donc pour tout T, alors à fortiori A<t> est abstraite également...

    ce que tu peux faire c'est F qui hérite de A<T>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    class F: public A<T>{};
    F<int> f;
    mais je sais pas trop ce que tu veux faire, notamment le coup de T abstraite, rien ne t'empêches de la construction de F de donner un t

  3. #3
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Citation Envoyé par Spirine Voir le message
    Bonjour à tous,
    J'aimerais savoir s'il était possible de créer l'architecture suivante:
    • Une classe mère abstraite et template A. Son type générique doit absolument hériter T.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    tempalte<class U>
    struct A
    { virtual void foo() =0; };
    Citation Envoyé par Spirine Voir le message
    • Une classe abstraite T.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    struct T
    { virtual void foo() =0; };
    Citation Envoyé par Spirine Voir le message
    • Des classe t, qui héritent chacune de T.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    struct t1 : T
    { };
     
    struct t2 : T
    { };
    Citation Envoyé par Spirine Voir le message
    • Des classes F. Chacune d'entre elle est une spécialisation, non pas de A, mais pour un certain t, de A<t>. Donc F est une implémentation de A pour un seul t.
    Je ne comprends pas ta phrase, mais je suppose que tu veux faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    struct F1 : A<t1>
    { };
     
    struct F2 : A<t2>
    { };
    Citation Envoyé par Spirine Voir le message
    J'ai déjà essayé mais cela n'a pas été concluant... En effet, il doit y avoir un problème avec l'utilisation à la fois de polymorphisme statique (template) et dynamique(A est abstraite).
    Merci d'avance pour vos réponse!
    Il existe en effet des limitations, mais pas pour faire ce que tu viens de mentionner à priori.

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

    Informations professionnelles :
    Activité : aucun

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

    Notes juste Flob, que je n'aurais pas utilisé le principe de la fonction virtuelle pure pour rendre la classe A<U> abstraite... Le compilateur a généralement énormément de mal à se rendre compte qu'une fonction déclarée comme virtuelle pure dans une classe template a bel et bien été définie dans les classes dérivée (ce qui devrait avoir pour résultat de rendre la classe dérivée instanciable )

    A vrai dire, comme le rôle des template est de générer du code spécifique à chaque spécialisation du paramètre template à la compilation, je ne sais même jamais si la norme autorise l'idée d'une fonction virtuelle dans une classe template destinée à servir de classe de base dans un hiérarchie

    Toujours est-il qu'une classe "abstraite" n'est rien d'autre qu'une classe qui ne peut pas être instanciée d'elle-même dans le sens où il faut qu'elle soit forcément instanciée au travers d'une des classes qui en dérivent. Il n'est donc pas forcément nécessaire de recourir à la technique de la fonction virtuelle pure pour y parvenir, car il "suffit" de placer le constructeur (et le destructeur, que l'on aura pris soin de ne surtout pas déclarer virtuel, tant qu'à faire) dans l'accessibilité protégée. Toute tentative d'instanciation de la classe par elle même se soldera par une erreur au motif que le constructeur (le destructeur) est protégé dans ce contexte. Mais l'instanciation des classes dérivées sera autorisée car... les fonctions membres de la classe dérivées (dont le constructeur et le destructeur) ont parfaitement le droit d'accéder aux éléments protégés de leur classe de base (et de toutes leurs classes parentes pour lesquelles il y a eu recours à l'héritage public )

    Enfin, bref, au final, une classe abstraite template prendra tout simplement la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename T>
    class Abstract{
    public:
        /* les fonctions publiques spécifiques */
    protected:
        Abstract(/* paramètres éventuels */ ){/* utilisation éventuelles des paramètres (par les différents biais possibles */}
        ~Abstract(){}
        /* autres membres et fonctions protégés*/
    private:
        /* les membres et fonction privés */
    };
    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

  5. #5
    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
    Notes juste Flob, que je n'aurais pas utilisé le principe de la fonction virtuelle pure pour rendre la classe A<U> abstraite... Le compilateur a généralement énormément de mal à se rendre compte qu'une fonction déclarée comme virtuelle pure dans une classe template a bel et bien été définie dans les classes dérivée (ce qui devrait avoir pour résultat de rendre la classe dérivée instanciable )
    Je comprends pas a quoi tu penses.

    A vrai dire, comme le rôle des template est de générer du code spécifique à chaque spécialisation du paramètre template à la compilation, je ne sais même jamais si la norme autorise l'idée d'une fonction virtuelle dans une classe template destinée à servir de classe de base dans un hiérarchie
    Quel serait le probleme des virtuelles dans les templates de classes? (j'aime pas "classe template" qui laisse penser que c'est une classe, "class template" en anglais est un template -- la norme a joue un temps sur la difference entre "class template" et "template class", ce dernier etant bien une classe puisque ca designait ce qu'on appelle une instanciation).

    Chaque instanciation d'un template de classe est bien une classe et peut avoir des virtuelles.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Je comprends pas a quoi tu penses.
    Au problème qu'il pourrait y avoir avec une fonction virtuelle qui est (implicitement) déclarée inline, avec tout ce que cela comporte d'incompatibilité entre l'inlining et l'appel à une Vtbl.

    Je sais avoir déjà posé ce genre de question et n'avoir jamais "percuté" sur la réponse. Et il me semble avoir rencontré certaines situations dans lesquelles le compilateur se plaignait qu'un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
    template <typename T>
    class Base{
        public:
            virtual void foo()  = 0; //fonction virutelle pure --> classe abstraite
    };
     
    class Derivee : public Base<nimportequeltype>{
        virtual void foo() ; // ce n'est plus une fonction virtuelle ici
    };
    avait pour résultat de laisser une fonction virtuelle pure et de rendre la classe Derivee abstraite. Je n'ai plus de code sous la main à ce sujet, il n'est pas impossible que ce soit, entre autres à cause d'un éventuel argument qui devrait être de type T dans Base, mais je n'ai absolument aucune certitude (je ferai mes recherches )
    Quel serait le probleme des virtuelles dans les templates de classes? (j'aime pas "classe template" qui laisse penser que c'est une classe, "class template" en anglais est un template -- la norme a joue un temps sur la difference entre "class template" et "template class", ce dernier etant bien une classe puisque ca designait ce qu'on appelle une instanciation).
    Justement, j'en vois deux que je viens de citer (et je parle bel et bien d'une situation telle que présentée par mon code, non d'une situation dans laquelle ce serait la classe template qui hérite d'une classe "classique" ):
    • l'incompatibilité entre la déclaration inline qui est implicite pour toute fonction définie dans la définition de la structure et l'utilisation (la création) d'une table de fonctions virtuelles et
    • certaines difficultés que le compilateur pourrait avoir à constater que l'implémentation de la fonction virtuelle dans la classe dérivée correspond bel et bien à l'implémentation de la fonction que l'on a explicitement indiquée comme étant virtuelle pure dans la classe de base (qui serait une tempalte class ).


    Quoi qu'il en soit, comme il existe des solutions qui nous permettent d'éviter qu'une classe (qu'il s'agisse de template class ou non) soit instanciable sans passer par une classe dérivée sans avoir à sortir la virtualité et les fonctions virtuelles pures, en déclarant simplement le destructeur dans l'accessibilité protégée (cela suffit généralement), à défaut de savoir si le PO a effectivement besoin d'une fonction virtuelle pure (et ca, seule une analyse correcte de ses besoins pourra nous le dire), je crois que je préférerai partir sur un destructeur protégé que sur une fonction virutelle pure (quelle que soit cette fonction) "par défaut"

    Après tout, la virutalité du destructeur n'est pas du tout obligatoire pour une classe de base si on ne se trouve pas dans une situation dans laquelle il faut détruire un objet du type dérivé "passant pour être" du type de base... On a donc tout à gagner à rendre la création (et ici surtout la destruction) du type de base sans passer par le type dérivé impossible
    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 koala01 Voir le message
    Au problème qu'il pourrait y avoir avec une fonction virtuelle qui est (implicitement) déclarée inline, avec tout ce que cela comporte d'incompatibilité entre l'inlining et l'appel à une Vtbl.
    Ca n'a en effet guere de sens de mettre une fonction virtuelle inline (c'est une remarque que je fais regulierement en revue de code), mais ca n'a jamais gene les compilateurs (je n'aurais pas l'occasion de faire la remarque sinon), en particulier avec les templates qui doivent de toute maniere deja gerer les problemes de duplications (pour les statiques, pour pouvoir comparer les pointeurs de fonction). (En absence de template, j'ai deja vu des problemes avec des classes qui ne resultaient pas d'instanciation de templates et avaient toutes leur virtuelles inline; ca doit faire 10 ans que je n'en ai plus vu, je ne sais pas si c'est parce que les compilateurs ont abandonne l'heuristique de mettre la vtbl dans l'unite qui defini la premiere fonction virtuelle ou parce que le cas ne s'est plus presente parce qu'il a peu de sens.)

    (je ferai mes recherches )
    Le cas exact m'interesse.

    Justement, j'en vois deux que je viens de citer (et je parle bel et bien d'une situation telle que présentée par mon code, non d'une situation dans laquelle ce serait la classe template qui hérite d'une classe "classique" ):
    • l'incompatibilité entre la déclaration inline qui est implicite pour toute fonction définie dans la définition de la structure et l'utilisation (la création) d'une table de fonctions virtuelles et
    Voir ci-dessus, il n'y a pas d'incompatibilite formelle. Ca a pose des problemes avec un heuristique d'implementation si toutes les virtuelles etaient inline, mais l'heuristique n'a ma connaissance n'a jamais ete utilisee pour les templates (qui n'ont pas besoin de cette heuristique avec le mecanisme d'instanciation habituel).

    • certaines difficultés que le compilateur pourrait avoir à constater que l'implémentation de la fonction virtuelle dans la classe dérivée correspond bel et bien à l'implémentation de la fonction que l'on a explicitement indiquée comme étant virtuelle pure dans la classe de base (qui serait une tempalte class ).
    Je ne vois vraiment pas quelle difficulte il y a. (ca n'a jamais exclus les bugs, mais les problemes dont tu as peur me semblent etre de cette nature).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  8. #8
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Je réponds à l'op en respectant la norme à la lettre (sans plus d'information). Normativement, une classe abstraite a au moins une fonction virtuelle pure, je ne cherche pas plus loin. Si l'op précise ce qu'il veut faire ou le sens qu'il donne à classe abstraite, alors j'aviserais (même si pour moi, en acceptant une définition plus large de classe abstraite, je pense qu'une fonction virtuelle pure est encore le plus simple pour réaliser une classe abstraite).

    Pour le coup inline/virtual, en effet ça a peu de sens de s'attendre à ce que l'appel soit en effet inliné (même si ça peut arriver si l'appel permet au compilateur de le faire, mais ce n'est pas le cas usuel à priori). Par contre l'autre utilité de inline, c'est de jouer avec l'ODR, et dans ce cas déclarer une fonction comme virtuelle et inline n'est pas problématique.

  9. #9
    Invité
    Invité(e)
    Par défaut
    à partir de Hier, 11h24
    pourquoi parler de template, si la discussion se fait entre inline et virtual?

  10. #10
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    parce qu'une template est intégralement inline...
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  11. #11
    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 leternel Voir le message
    parce qu'une template est intégralement inline...
    Ah bon? Le corps des fonctions membres de mes templates de classes sont rarement inline, en fait, ils le sont dans exactement les memes conditions que les fonctions membres des classes non templates.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  12. #12
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Par définition d'une template, ils le devraient l'être.

    Inline ne signifie pas "défini dans la déclaration", mais "défini à l'identique dans toutes les unités de compilation".

    Avec deux .cpp, une fonction (normale) inline sera compilée deux fois, mais unifiée par l'édition de lien.
    Tandis qu'une fonction non-inline (offline?) sera compilée une seule fois, et simplement "extern" jusqu'à l'édition de lien.

    L'avantage premier d'inline, c'est que le compilateur peut du coup optimiser l'appel de la fonction.

    Pour les templates, ca va plus loin, mais tu auras le même problème.
    La template de classe ne défini pas une classe, mais plusieurs d'un coup.
    Il me semble que les fonctions sont "magiquement" inlinées.

    Cela dit, j'ai un doute soudain.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  13. #13
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    @leternel: Non, les template ne sont pas magiquement inline, par contre template et inline partagent une similitude au niveau de l'ODR (ce que tu expliques en détaillant avec les unités de compilation).

  14. #14
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    J'ai toujours cru le contraire.
    Je crois que j'ai encore gagné un billet pour la norme
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    En fait, elles sont implicitement inline si elles sont définies directement dans la définition de la classe (comme toute fonction membre d'une classe "classique")...

    Le fait est que l'on doit fournir le code (C++) des fonctions membres de classe génériques (pour éviter le terme de classe templates) pour que le compilateur puisse générer le code binaire correspondant à chaque instanciation de la classe.

    Par "facilité" (enfin, on se comprend ) certains vont systématiquement implémenter les fonctions membres de leurs classes génériques directement dans la définition de la classe, ce qui aura pour effet de les déclarer implicitement inline (vu que c'est ce que la norme prévoit pour ce cas de figure).

    Mais d'autres préféreront travailler de manière plus "classique" , en veillant à séparer la déclaration et l'implémentation, quitte à ce que l'implémentation prenne place dans le fichier d'en-tête de la classe ou dans un fichier séparé (impl? incl?) qui sera forcément inclus à la fin du fichier d'en-tête (ou en tout cas, au plus tard avant la première instanciation générique de la classe dans le fichier d'implémentation qui utilise une instanciation de la dite classe ).

    Mais, à ce moment là, la fonction n'étant pas implémentée dans la définition de la classe, elle n'a absolument aucune raison d'être considérée comme inline par le compilateur. Sauf que, en pratique, il faut qu'elle le soit pour satisfaire à l'ODR . Si tu travailles de cette manière, tu dois donc veiller à déclarer explicitement tes fonctions inline (ou à utiliser des méthodes comme l'instanciation explicite, mais ca, c'est tout un débat )
    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

  16. #16
    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 leternel Voir le message
    Par définition d'une template, ils le devraient l'être.
    Tu me donnes la definition de template qui implique cela?

    Inline ne signifie pas "défini dans la déclaration", mais "défini à l'identique dans toutes les unités de compilation".
    Non, ce n'est pas la definition d'inline, c'est une contrainte que les fonctions inlines doivent respecter.

    Citation Envoyé par C++ 11
    7.1.2/2 A function declaration (8.3.5, 9.3, 11.3) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.

    7.1.2/3 A function defined within a class definition is an inline function. The inline specifier shall not appear on a block scope function declaration.90 If the inline specifier is used in a friend declaration, that declaration shall be a definition or the function shall have previously been declared inline.

    7.1.2/4 An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case
    Et à part les membres ayant une définition par défaut, je ne connais pas d'autres endroits où des fonctions sont définies comme inlines.

    Pour les templates, ca va plus loin, mais tu auras le même problème. La template de classe ne défini pas une classe, mais plusieurs d'un coup. Il me semble que les fonctions sont "magiquement" inlinées.
    Pas à ma connaissance. Et chercher inline dans le chapitre de la norme consacrée aux templates ne donne rien qui suggère cela.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  17. #17
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    @koala01: Non, inutile d'indiquer inline si tu définis tes fonctions membres template hors de ta classe, elles respecteront quand même l'ODR. C'est justement à ca que je pense quand je dis que template et inline partagent une propriété commune vis à vis de l'ODR :
    There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
    external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
    of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
    which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
    appears in a different translation unit, and provided the definitions satisfy the following requirements.

  18. #18
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Merci pour cet éclaircissement.

    Comme quoi, j'ai bien fait de répondre, j'aurai appris quelque chose.
    Encore merci!
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Pas à ma connaissance. Et chercher inline dans le chapitre de la norme consacrée aux templates ne donne rien qui suggère cela.
    en fait, c'est une des conséquences logiques du fait que le compilateur a besoin du code des fonctions génriques (ou des fonctions membres de classes génériques) pour pouvoir fournir le code binaire qui correspond à cette fonction.

    A moins d'avoir recours à l'instanciation explicite (entre autres techniques) pour n'avoir pas à inclure l'implémentation des fonctions membres dans les différentes unités de compilation qui les utilisent, le compilateur générera le code binaire des fonctions membres pour une spécialisation donnée dans chaque unité de compilation où l'implémentation sera présente.

    Je vais prendre un exemple simple pour essayer d'expliquer ce que je veux dire... Soit une classe générique proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <typename T>
    class MyClass{
    public:
        void foo();
        /* tout le reste */
    };
    Si on décide d'utiliser cette classe avec T = int, il faut que l'éditeur de liens puisse trouver un symbole pour la fonction void MyClass<int>::foo. Autrement, il nous jettera avec un "undefined reference to 'void MyClass::foo'"... rien de plus logique en somme

    Si tu n'as pas recours à l'instanciation explicite, et que tu utilise la classe avec T = int dans fichier1.cpp, tu devras donc avoir quelque chose qui ressemblera à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <MyClass.hpp>
    /* D'une manière ou d'une autre, il faudra que l'implémentation de MyClass::foo soit 
      * présente ici pour que le compilateur puisse en générer le code binaire
      * (inclusion d'un *.inc / *.impl? )
      */
    void bar(/* .... */){
       MyClass<int> obj;
       obj.foo() /* sinon, l'éditeur de liens ne sera pas content ici */
       /* ... */
    }
    Même cause, mêmes effets : si tu dois utiliser MyClass avec T = int dans fichier2.cpp, tu devras agir de la même manière, ce qui fait que ce fichier pourrait ressembler à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <MyClass.hpp>
    /* D'une manière ou d'une autre, il faudra que l'implémentation de MyClass::foo soit 
      * présente ici pour que le compilateur puisse en générer le code binaire
      * (inclusion d'un *.inc / *.impl? )
      */
    void bar(/* .... */){
       MyClass<int> obj;
       obj.foo() /* sinon, l'éditeur de liens ne sera pas content ici */
       /* ... */
    }
    Mais si on n'indique pas à l'éditeur de liens qu'il risque de trouver le symbole correspondant à la fonction MyClass<int>::foo dans plusieurs unité de compilation (ce qui arrivera, vu qu'il va le trouver dans fichier1.o et dans fichier2.o), il ne sera pas d'avantage content et il va également nous jeter au prétexte de "multiple definitions for MyClass<int>::foo ".

    Tout cela parce que la norme n'indique nulle part que le code binaire correspondant à une fonction générique (ou à une fonction membre d'une clase générique) doit être considéré comme étant "spécifique à l'unité de compilation" dans laquelle il se trouve

    Si l'on veut éviter ce problème, il faut s'arranger pour que la fonction soit inline, soit implicitement (en implémentant la fonction dans le corps de la classe) soit explicitement. Non pas pour permettre la substitution de l'appel à la fonction appelée par le code correspondant, mais bien pour que le compilateur place une information destinée à l'éditeur de liens lui indiquant que le symbole correspondant à la fonction risque d'apparaitre dans différentes unités de compilation (en gros, dans toutes les unités de compilation dans lesquelles nous utiliserons la même spécialisation de la même classe générique).
    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

  20. #20
    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, c'est une des conséquences logiques du fait que le compilateur a besoin du code des fonctions génriques (ou des fonctions membres de classes génériques) pour pouvoir fournir le code binaire qui correspond à cette fonction.
    Je ne vois toujours pas, quel que soit celui des deux points de vue suivants que je prends:

    - formel: inline est une propriété formelle des fonctions, les fonctions n'ont cette propriété que si la norme le dit. La norme considère l'aspect template et inline de manière indépendante.

    - pratique: inline désigne l'aspect génération de code. Le compilateur lorsqu'il voit le code a un peu plus d'opportunités pour rendre les instanciations inline, mais c'est pas une obligation et qu'il ait le code ou non le compilateur ne va pas inliner de grosses fonctions. Les fonctions formellement inline ne le sont pas nécessairement en pratique (même si le compilateur peut considérer qu'il faut lefavoriser), les fonctions pratiquement inline ne le sont pas nécessairement formellement. Avoir la définition de la fonction lors de la compilation aide (c'est pour ça que la version formelle l'impose), mais n'est pas nécessaire (voir les optimisations faites au link, inline est une de celles qui peuvent être faites relativement facilement sur du code objet bien qu'a moindre bénéfice que sur une représentation intermédiaire).

    A moins d'avoir recours à l'instanciation explicite (entre autres techniques) pour n'avoir pas à inclure l'implémentation des fonctions membres dans les différentes unités de compilation qui les utilisent, le compilateur générera le code binaire des fonctions membres pour une spécialisation donnée dans chaque unité de compilation où l'implémentation sera présente.
    Il y a trois mécanismes d'instanciations utilisés en pratique. Le dominant est bien celui auquel tu penses, que David et Nicolas appellent "greedy instantiation", on génère partout et laisse le linker jeter ce qui n'est pas nécessaire. Il y en a deux autres: "queried instantiation", on a une db qui contient les instances, le compilateur s'assure que la db contient ce qu'il faut (et ne fait rien si c'est déjà le cas) et le linker prend les instanciations dont il a besoin; "iterated instantiation", une db indique quelles unités de compilation doivent contenir les instanciations, s'il se rend compte qu'il manque quelque chose le linker complète la db et recompile les unités qu'il faut. (En passant, cet aspect est indépendant du modèle de compilation).

    Aucun des trois mécanismes n'implique que les instanciations de fonctions soient inlines.

    Tout cela parce que la norme n'indique nulle part que le code binaire correspondant à une fonction générique (ou à une fonction membre d'une clase générique) doit être considéré comme étant "spécifique à l'unité de compilation" dans laquelle il se trouve
    Heureusement que les instanciations sont globales. (Si ce n'était pas le cas, impossible d'utiliser des templates dans une fonction appelée en dehors de la CU).

    Si l'on veut éviter ce problème, il faut s'arranger pour que la fonction soit inline, soit implicitement (en implémentant la fonction dans le corps de la classe), soit explicitement.
    C'est quoi ta définition de inline? Parce que je pense que le problème est là.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

Discussions similaires

  1. Spécialisation de template particulière
    Par Flo. dans le forum Langage
    Réponses: 4
    Dernier message: 25/03/2009, 22h18
  2. Spécialisation de template parametre avec Enum
    Par 3DArchi dans le forum Langage
    Réponses: 4
    Dernier message: 24/09/2008, 15h21
  3. Spécialisation de template
    Par bobyjoe dans le forum Langage
    Réponses: 18
    Dernier message: 13/12/2007, 21h52
  4. Réponses: 8
    Dernier message: 24/04/2007, 22h09
  5. Réponses: 7
    Dernier message: 01/01/2006, 03h28

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