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 :

Restreindre le paramètre d'un Template via Heritage


Sujet :

Langage C++

  1. #1
    Membre du Club
    Inscrit en
    Novembre 2006
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 8
    Par défaut Restreindre le paramètre d'un Template via Heritage
    Bonjour à tous,

    depuis quelques temps, je rencontre le problème suivant :

    Je dois mettre en place une classe qu'on va appeler ALGO qui utilise un template classe A :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    template <class A>
    class ALGO {
    private:
      A m_attribut;
    public:
     /* ... */
    };
    Ce que je souhaite faire c'est limité l'utilisation du paramètre template "class A" à des classes héritant d'une classe virtuelle C.

    Quelqu'un saurait-il comment faire ?

    Merci d'avance.


    Samagace

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 48
    Par défaut
    Bonjour,
    Tu peux utiliser les Static Assert de Boost, par exemple dans le constructeur de ta classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #include <boost/type_traits.hpp>
    #include <boost/static_assert.hpp> 
    #include "C.hpp"
    ...
    ...
    template<class A>
    ALGO<A>::ALGO()
    {
      BOOST_STATIC_ASSERT((boost::is_base_of<C, A>::value));
    }
    Si A n'est pas une classe fille de C tu auras une erreur de compil'

  3. #3
    Membre du Club
    Inscrit en
    Novembre 2006
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 8
    Par défaut
    Merci,

    je ne savais qu'il existait ça dans BOOST, mais il n'y a aucun moyen de faire cela nativement en C++ ?

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 48
    Par défaut
    Il doit certainement exister des solutions, mais je ne vois pas...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut, et bienvenue sur le forum.

    D'abord, la question qui tue: "pourquoi voudrais tu poser cette limitation ".

    Je la justifie quand même un peu: typiquement, le but de la programmation générique est de... laisser le plus grand choix possible quant à l'utilisation que l'on pourra faire des fonctions et des classes template

    Qui te dit que tu n'auras pas un utilisateur farfelu qui arrivera avec une classe compatible du point de vue de l'interface avec ta classe de base et qui voudra (à juste titre) utiliser ta classe template

    Ensuite, je présumes (peut être à tord ... n'hésite pas à me dire que je me trompes ) que ton problème est en fait surtout de t'assurer que les objets réellement passés disposeront d'une interface particulière...

    Mais là, tu peux être rassuré: tout type n'exposant pas l'interface à laquelle tu espères avoir accès dans ta classe provoquera irrémédiablement une erreur de compilation sous prétexte que telle ou telle fonction, tel ou tel type imbriqué est indisponible.

    Bon, d'accord, l'erreur est parfois cryptique... Mais elle sera de toutes manière présente.

    En outre, il faut savoir que, quoi qu'il arrive, ta classe template telle que tu la présente aura pour résultat de faire appartenir ALGO<derivee1> et ALGO<derivee2> à deux hiérarchies de classe différentes, même si derivee1 et derivee2 hérite, de manière directe ou indirecte, de manière virtuelle ou non, d'une classe commune...

    Si tu veux qu'il en aille autrement, il y aura sans doute des mesures à prendre

    Enfin, mais ce n'est qu'un détail: C++ autorise l'héritage virtuel afin de résoudre le problème de l'héritage en diamant, mais le seul fait de se retrouver dans une telle situation révèle souvent (parce que ce n'est pas toujours le cas ) un problème de conception sous-jasent, induit entre autre par une décision inopportune d'utiliser l'héritage, décision qui aurait sans doute été écartée si tu avais correctement appliqué le principe de substitution de Liskov

    Je ne dis pas que c'est ton cas car je n'en connais pas assez sur ton projet pour l'affirmer, mais je fais cette mise en garde de manière générale pour, éventuellement, t'inciter à revoir ta conception
    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

  6. #6
    Membre du Club
    Inscrit en
    Novembre 2006
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 8
    Par défaut
    Bonjour et merci pour l'accueil !

    Pour preciser davantage la raison de cette restriction j'ai simplement trouve plus propre d'imposer une interface afin de massurer que les bons types et arguments sont utilisés.
    En effet si par exemple l'utilisateur utilise des unsigned int la ou j'attend des int ou des doubles, ou même d'autres types "compatibles" lors de la compil, le comportement ne pourra etre certifie comme correct.
    D'où mon idée, surement un brin barbare, de contraindre qqchose qui par sa conception permet de lever des contraintres.
    Je reste cependant ouvert a toute autre siggestion.


    Samagace

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Tu pourrais peut être envisager l'utilisation de traits de politiques.

    Si tu crées une structure proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <typename>
    struct MyTrait;
    Que tu la spécialise uniquement pour les type compatibles sous la forme de
    Code : 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
    template <>
    struct MyTrait<size_t>
    {
        typedef size_t value_type;
        typedef size_t & reference_type;
        typedef size_t * pointer_type;
        typedef size_t const const_type;
        typedef size_t volatile volatile_type;
    };
    template <>
    struct MyTrait<double>
    {
        typedef double value_type;
        typedef double & reference_type;
        typedef double * pointer_type;
        typedef double const const_type;
        typedef double volatile volatile_type;
    };
    et que tu ne la spécialise pas pour les autres types primitifs

    il peut te suffire d'écrire ta classe sous la forme de
    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 /* les autres arguments template */>
    class MyClass
    {
        public:
        typedef MyTrait<T>::value_type value_type;
        typedef MyTrait<T>::reference& reference_type;
        typedef MyTrait<T>::pointer_type * pointer_type;
        typedef MyTrait<T>::const_type const const_type;
        typedef MyTrait<T>::volatile_type volatile volatile_type;
        /* la suite */
     
    };
    tu auras la certitude d'obtenir une erreur de compilation si tu fournis à MyClass autre chose qu'un size_t ou qu'un double (selon l'exemple que je donne) au motif que "MyTrait<T>::value_type n'est pas déclaré" (avec T : le type choisi)", et de même pour les autres.

    Simple et efficace

    Tu n'auras même plus à recourir à l'héritage multiple ou à l'héritage virtuel: tout ce que tu devra faire, c'est t'assurer que le trait de politique fass partie des arguments template
    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 du Club
    Inscrit en
    Novembre 2006
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 8
    Par défaut
    Merci,
    Il s'agit en effet d'une methode interessante!
    Je reste cependant un peu sceptique :
    J'utilise de nombreux types et cette methode restreint si j'ai bien compris le panel de types utilisables.
    Mais est-ce que je suis assuré que le trait X ets utilise dans
    la methode A et le traits Y dans la methode B et pas l'inverse ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par SamAgace Voir le message
    Merci,
    Il s'agit en effet d'une methode interessante!
    Je reste cependant un peu sceptique :
    J'utilise de nombreux types et cette methode restreint si j'ai bien compris le panel de types utilisables.
    Absolument pas...

    A vrai dire, MyClass peut parfaitement suffire en l'état, et être renommée, afiin de prendre une valeur documentée en PrimitiveCheck:
    template <typename T>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct PrimitiveCheck
    {
        typedef MyTrait<T>::value_type value_type;
        typedef MyTrait<T>::reference& reference_type;
        typedef MyTrait<T>::pointer_type * pointer_type;
        typedef MyTrait<T>::const_type const const_type;
        typedef MyTrait<T>::volatile_type volatile volatile_type;
    };
    La seule chose que tu auras à faire, c'est de fournir un type primitif qui sera vérifié par cette classe.

    Ce sera d'autant plus nécessaire que, si tu veux pouvoir choisir le type primitif, il faudra bien que... tu dispose de value_type (essentiellement).

    Tu peux donc parfaitement avoir une classe, qui utilise au choix des doubles ou des int et un autre argument template, qui prendrait la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    template <typename primitive, class Type>
    class AClass
    {
        public:
        /* on s'assure qu'elle n'utilise que des int ou des doubles 
         * Comme on doit pouvoir utiliser le type double ou le type int dans
         * nos fonctions, on va le nommer "primitive_type"
         */
        typedef typename PrimitiveCheck::value_type primitive_type; //check intégré :D
        void foo(primitive_type v)
        {
            /*ce qui doit être fait */
        }
     
    };
    Mais est-ce que je suis assuré que le trait X ets utilise dans
    la methode A et le traits Y dans la methode B et pas l'inverse ?
    Si tu sais que tu veux un type bien particulier pour un paramètre, il te suffit de l'indiquer explicitement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    template <class Type>
    class MyClass
    {
        public:
            void intFoo(size_t i)
            {
            }
            void doubleFoo(double d)
            {
            }
    };
    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 du Club
    Inscrit en
    Novembre 2006
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 8
    Par défaut
    Ok
    Malgres tout il reste des choses a peaufiner mais je pense que la piste que tu m'as donné est intéressante.
    Merci beaucoup, je clos le topic!

    Samagace

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Nous sommes évidemment d'accord que le typedef que tu choisira de créer correpondra... à tes besoins, hein

    Si tu as, cela peut arriver, explicitement besoin d'un pointeur sur entier, tu créera un typedef sur... PrimitiveCheck<T>::pointer_type
    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

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 10/01/2008, 13h50
  2. renseignement d'un paramètre d'une requete via le VBA
    Par raynor911 dans le forum Requêtes et SQL.
    Réponses: 7
    Dernier message: 13/12/2006, 14h42
  3. Réponses: 2
    Dernier message: 23/08/2006, 10h42
  4. Passage de paramètres vers un template xsl
    Par Le lag dans le forum XSL/XSLT/XPATH
    Réponses: 1
    Dernier message: 19/04/2006, 18h20
  5. Réponses: 3
    Dernier message: 16/01/2006, 11h34

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