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 :

Petite question sur le CRTP


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut Petite question sur le CRTP
    Je cherche à factoriser au maximum du code partagé entre plusieurs classes qui définissent des machines à états, sans utiliser d'héritage et de méthodes virtuelles. J'ai donc regardé du côté des templates, et j'en suis arrivé à me dire que le CRTP pouvait être une bonne idée pour ce faire. J'ai donc écrit un code qui ressemble vaguement à ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    template<class T>
    class A
    {
    public:
            typename T::toto val;
            int a[T::nbelem];
    };
     
    class B : public A<B>
    {
    public:
            enum toto { a, b, c, nbelem };
            toto f() { return val; }
    };
    Le problème est que ça ne compile pas :

    test.cxx: In instantiation of ‘A<B>’:
    test.cxx:16: instantiated from here
    test.cxx:5: error: invalid use of incomplete type ‘class B’
    test.cxx:15: error: forward declaration of ‘class B’
    test.cxx:6: error: incomplete type ‘B’ used in nested name specifier
    test.cxx:6: error: array bound is not an integer constant
    test.cxx: In member function ‘B::toto B::f()’:
    test.cxx:19: error: ‘val’ was not declared in this scope
    Je peux contourner ce problème en "sortant" la définition de mon enum dans une autre classe, et en écrivant le code suivant (je n'ai pas touché à A) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class paramB
    {
    public:
            enum toto { a, b, c, nbelem };
    };
     
    class B : public A<paramB>
    {
    public:
            paramB::toto f() { return val; }
    };
    Ça me convient bien, et je pense que je vais faire comme ça. Par contre, j'aimerai bien comprendre pourquoi le premier code ne compile pas. Si quelqu'un a une explication...

  2. #2
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Le CRTP exploite le fait que les fonctions membres de la classe de base ne sont pas encore connues. Là, tu attaques des attributs.

    A la place, tu peux utiliser des structures de traits
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    template <typename T> struct traits {};
    class B;
    template <> struct traits<B> {
        enum toto { a, b, c, nbelem };
    };
     
    template<class T>
    class A
    {
    public:
        typedef typename traits<T>::toto toto;
        toto m_val;
        int m_a[traits<T>::nbelem];
    };
     
    class B : public A<B>
    {
    public:
        toto f() { return m_val; }
    };
    NB: j'avoue que j'ai un petit doute en ce qui concerne la déclaration anticipée de B.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  3. #3
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Merci, je vois l'idée, par contre, je ne vois pas l'avantage de la classe de traits génériques par rapport au double paramétrage que je fais...

    Mon seul problème actuellement, c'est que mes enum sont définis dans paramB, et donc, je dois jouer avec friend et l'utilisation des valeurs des enum dans B est un peu pénible.

    Je ne crois pas que ta proposition règle ce problème-là, mais j'ai peut-être loupé quelque chose.

    Ah, il y a une chose que j'ai oublié de préciser. Dans la classe mère A<paramB,B>, j'ai besoin d'appeler des méthodes de la classe fille. Ce que je peux faire facilement en castant le this, puisque je suis sûr que this est de type B (usage normal du CRTP si j'ai bien compris). Je ne vois pas trop comment faire la même chose avec des classes de traits.

    Enfin, pour revenir au fait que cela ne fonctionne pas si je mets la déclaration des enums dans B, je comprends que c'est lié à ça :

    This is valid only if the size of X<T> can be determined independently of T
    et que donc, il n'y a pas de solution autre que les définir ailleurs que dans B.

  4. #4
    Alp
    Alp est déconnecté
    Expert confirmé

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    En combinant CRTP et Traits, tu peux définir des attributs et ne les récupérer qu'au moment où tu utilises traits<B>.
    En combinant CRTP et Policies, tu peux définir des fonctions et ne les lier à la classe mère qu'au moment où tu utiliserais PolicyB.

    Il s'agirait pour les Policies de faire du polymorphisme statique. Ce genre d'utilisation permet d'avoir une modularité et une personnalisation de tes classes à volonté.

    Je te conseille de lire ceci : http://alp.developpez.com/tutoriels/traitspolicies/

Discussions similaires

  1. [ATL] Petite question sur les progress bar
    Par MrMaze dans le forum MFC
    Réponses: 1
    Dernier message: 06/05/2005, 09h40
  2. [Visuel XP] Petite question sur le theme XP...
    Par ZoumZoumMan dans le forum C++Builder
    Réponses: 12
    Dernier message: 20/01/2005, 14h41
  3. petite question sur le composant IBX ...
    Par vbcasimir dans le forum Bases de données
    Réponses: 4
    Dernier message: 05/01/2005, 10h33
  4. Réponses: 3
    Dernier message: 08/12/2004, 13h58
  5. Petite question sur les performances de Postgres ...
    Par cb44 dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 13/01/2004, 13h49

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