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 :

Templates : restreindre l'instanciation à une hiérarchie de types


Sujet :

Langage C++

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut Templates : restreindre l'instanciation à une hiérarchie de types
    Hello,

    Disons que j'ai :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<typename T>
    class tempClass
    {
       ...
    };
    Comment faire en sorte que tempClass ne soit instanciable qu'avec des types descendant du même parent (avec le parent lui-même), la hiérarchie étant construite via CRTP ?...

    Merci.

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Par défaut
    Corrigez moi si je me trompe, mais a tu regarde du cote de <type_traits> avec std/boost::is_base_of<Base, Derived>?

    Edit : Le tout couple avec une static_assert

    Doc boost de la classe, je me souvenais plus de l'odre des template! http://www.boost.org/doc/libs/1_48_0...s_base_of.html

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 146
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    ne serait-pas possible en déclarant ça comme abstraite et en implémentant que pour les types spécifiques nécessaires ?

    Exemple de ce que j'ai en tête:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template< class T >
    class tempClass
    {
     void doSomething()=0;
    };
    class Parent {};
    template<>
    class tempClass<Parent>
    {
     void doSomething() {}
    };
    Ce qui, si ça fonctionne comme je l'espère, entraînera une erreur de compilation avec autre chose qu'un Parent (ou dérivé), avec une errreur de "cannot instatiate abstract class".
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    Bonjour,

    Pour cette dernière proposition, je crains fort que l'erreur de compilation survienne même avec les classe dérivées de « Parent »...

  5. #5
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    +1 à la réponse de victor_gasgas ; j'ajoute que les type traits ayant été intégré au TR1, il n'est pas nécessaire d'utiliser boost ou C++11 pour y avoir accès.

    Par contre, static_assert nécessite boost ou C++11 (mais on peut faire sans).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    template <class C, class P = Parent, bool defined = std::is_base_of<P,C> >
    class tempClass;
     
    template <class C, class P = Parent>
    class tempClass<C,P,true>
    {
    // ... le code de la classe
    }
     
    // pas de définition pour tempClass<C,P,false>, ce qui va provoquer 
    // une erreur à la compilation si C ne dérive pas de P.
    Ou quelque chose dans le style
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Comment dois-je interpréter l'absence d'implémentation avec ta première déclaration de template ?

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,
    Citation Envoyé par oodini Voir le message
    Comment dois-je interpréter l'absence d'implémentation avec ta première déclaration de template ?
    Justement, comme une déclaration de la classe template, et non comme sa définition

    On pourrait, en gros, dire qu'il s'agit d'une déclaration anticipée (en tout cas, c'est le terme connu qui s'en rapproche le plus ) permettant au compilateur de savoir que ta classe fonctionne avec "jusqu'à" trois paramètres template (les deux derniers ayant des type par défaut .

    Mets toi un instant à la place du compilateur, tu vas voir, le jeu est sympa

    En ligne 1 et 2, le compilateur apprend qu'il existe une classe nommée tempClass qui est une classe template prenant trois arguments, dont les deux derniers sont factulatifs (car on donne une valeur par défaut).

    Les arguments facultatifs disent que P est, à défaut d'indication contraire, de type Parent et que defined (le booléen) prend la constante renvoyée par is_base_of(P, C), c'est à dire true si la classe P est bel et bien d'un type de base de la classe C.

    Les lignes 5 à 9 fournissent une définition pour cette tempClass pour certains arguments template particulier, dont le fait que le booléen (defined ) vaut true, c'est à dire si le résultat de l'évaluation de is_base_of est bel et bien true

    De cette manière, si on vient à avoir 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
    12
    13
    class A
    {
        /* ...*/
    };
    class B : public A
    {
        /* ...*/
    };
     
    int main()
    {
        tempClass<B, A> temp;
    }
    is_base_of fournit bel et bien la constante true, vu que A est bien... la classe parent de B, et le compilateur trouve la définition de la classe correspondant à C = B, P = A, defined = true, et va donc l'utiliser (il n'y aura pas d'erreur de compilation )

    Par contre, si tu utilise le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class A
    {
        /* ...*/
    };
    /* !! pas d'héritage publique de A !!! */
    class B 
    {
        /* ...*/
    };
     
    int main()
    {
        tempClass<B, A> temp;
    }
    Le compilateur trouve la déclaration de la classe template qui fonctionne avec les arguments fournis : C = B, P = A, defined = false.

    Jusque là, il est content

    Sauf que, quand il va rechercher le constructeur (par défaut ici ) de tempClass, il ne va pas le trouver, vu que la seule défintion qu'il trouve (et donc pour laquelle il existe bel et bien un constructeur par défaut (dans le cas présent) correspond aux argument C = B, P = A, defined = true, et que defined vaut... false

    Il va donc sortir avec une erreur de compilation proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    cannot find tempClass<C, P, defined>::tempClass() 
        [with C = B, P = A, defined  = false ]
    Et c'est exactement ce que tu voulais : tempClass ne peut pas être utilisée si tu ne fournis pas effectivement une classe dérivée et sa classe mère (ou ancêtre)
    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

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Effectivement, merci, je comprend bien ce qu'il se passe à présent.

    Toutefois, le message n'est pas très clair, et un static_assert serait en effet bienvenu. :-)

  9. #9
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Citation Envoyé par oodini Voir le message
    Effectivement, merci, je comprend bien ce qu'il se passe à présent.

    Toutefois, le message n'est pas très clair, et un static_assert serait en effet bienvenu. :-)
    Ben, oui, c'est le but du static_assert, parce que si, ici, on a encore un message *relativement* clair, mais, quand c'est une instanciation d'une classe template instanciée depuis une classe template instanciée depuis une classe template, il devient vachement difficile de retrouver le message original ...

    Le problème, c'est que le static_assert nécessite soit boost soit C++11 re
    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

  10. #10
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Le problème, c'est que le static_assert nécessite soit boost soit C++11 re
    Ça tombe bien, ce nouveau projet est en C++11.

  11. #11
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Sans revenir sur la manière de parvenir à ce résultat, j'ai de gros doutes quand je vois ce genre de code : Y a-t-il vraiment une bonne raison de contraindre de manière si forte le template ("dériver de" est bien la contrainte la plus forte qui puisse exister) ?

    L'un des intérêts des templates est justement qu'ils peuvent "tomber en marche" avec des types qui n'ont pas été prévus spécifiquement pour ça à l'origine, modulo quelques ajustements.

    De mémoire, quand on bossait sur une version concepts de la biblitohèque standard, qui consistait justement à mettre en place des contraintes explicite sur les types acceptables par tel ou tel template, pas une seule fois sur l'ensemble de la bibliothèque standard il n'a été envisagé de mettre en place une contrainte "le type doit dériver de".
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  12. #12
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Nous n'avons pas d'information sur le but poursuivi par l'OP, qui avait une question orientée technique. Peut-être que ça peut parfois servir à renforcer la sémantique de la classe template: l'associer à un type tartempion qui se trouve avoir une fonction avec la bonne signature peut éventuellement être dépourvu de sens même si ça marche techniquement.
    Autre point de vue plus technique (même si je t'accorde que pour le coup on pourrait voir ça comme trop restrictif): obliger à faire dériver le type paramètre d'une classe abstraite définissant l'interface attendue pourrait être une manière de documenter l'interface en question.

  13. #13
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    Citation Envoyé par therwald Voir le message
    Nous n'avons pas d'information sur le but poursuivi par l'OP, qui avait une question orientée technique. Peut-être que ça peut parfois servir à renforcer la sémantique de la classe template: l'associer à un type tartempion qui se trouve avoir une fonction avec la bonne signature peut éventuellement être dépourvu de sens même si ça marche techniquement.
    On a rarement a faire ca. Si tel couplage devait exister et qu'il retrouve implanté comme ca, c'ets que le design a foiré a un moment.

    Il y a vraiment peu d'instances ou on a besoin d'une telle surspecification de template et lorsqu'il y en a besoin, mieux vaut changer ses parametres afin d'avoir un type template plus contraints au niveau de la definition.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 09/02/2011, 15h40
  2. Réponses: 7
    Dernier message: 22/02/2007, 16h57
  3. [template] Instanciation d'une liste de types pour un plugin
    Par Matthieu Brucher dans le forum C++
    Réponses: 6
    Dernier message: 11/01/2007, 07h54
  4. Réponses: 13
    Dernier message: 25/10/2006, 16h17
  5. Réponses: 2
    Dernier message: 18/10/2003, 14h42

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