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

Boost C++ Discussion :

Spirit / actors / philosophie


Sujet :

Boost C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut Spirit / actors / philosophie
    Bonjour,

    Merci à ceux qui lirons ce post, et encore plus à ceux qui pourront y répondre.

    Je débute en spirit, je dois en être à mon troisième parseur, et je dois que je n'aime pas beaucoup les habitudes que j'ai prise. Il y a sans doute une ou plusieurs erreurs dans ma façon de faire.

    Voici un cas concret. Je veux parser le texte suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    "{14,12}
    {18,4}
    {27,2}"
    Et mettre les valeurs dans un conteneur de structures, quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct A
    {
       int x,y;
    };
     
    typedef std::list<A*> Contenair 
    Contenair maListe;
    Pour le moment, j'utilise les foncteur suivants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    struct ReaderX
    {
       int x&;
       ReaderX(int& newX) :x(newX)
       {
       };
       void operator()(int val)
       {
          x = val;
       };
    };
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct ReaderY
    {
       int x&;
       Contenair cont;
       ReaderX(int& newX, Contenair & newContenair) : x(newX), cont(newContenair)
       {
       };
       void operator()(int val)
       {
          newContenair.push_back(new A(x,val));
       };
    };
    du coup, mon parsage ressemble à ç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
    15
    16
     
    Contenair maListe;
    int variable_locale;
    ReaderX(variable_locale)
    ReaderY(variable_locale, maListe)
     
    Rule_t rule = 
    *(
       ch_p{'{'} >>
       int_p[ReaderX] >> 
       ch_p{','} >>
       int_p[ReaderY] >> 
       ch_p{'}'};
    );
     
    parse(...,rule);
    On voit bien la philosophie de ce code : j'utilise un premier Actor qui se contente de mettre à jour une variable locale à l'aide d'une référence, puis j'utilise un second Actor qui crée mon objet en utilisant cette référence.

    On voit aussi bien que c'est absurde. Il me semble qu'il ne devrait y avoir qu'un unique Actor :
    • la propriété de la variable ne devrait pas appartenir au code appelant. En particulier, il n'y a pas de raison que quelqu'un d'autre que le foncteur ait accés à cette variable.
    • Si mes objets contenaient non-pas 2, mais 40 valeurs, il y aurait 40 variables locales "polluantes".


    Je suppose qu'une meilleure attitude serait quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Contenair maListe;
    Reader(maListe)
     
    Rule_t rule = 
    *(
       ch_p{'{'} >>
       int_p[Utilise_Fonction<Reader,setX>] >> 
       ch_p{','} >>
       int_p[Utilise_Fonction<Reader,setY>] >> 
       ch_p{'}'};
    );
    parse(...,rule);
    ou quelque chose comme ça.

    Merci à ceux qui pourront m'aider, ou simplement donner leur avis.

  2. #2
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Bonjour à nouveau,

    j'ai essayé l'approche suivante :
    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
    19
    20
    21
    22
    23
    24
    25
    struct Reader : public std::binary_function<int,int,void>
    {
       Contenair cont;
       int x,y;
       Reader(Contenair & newContenair) : cont(newContenair)
       {
       };
       void operator()(int type,int val)
       {
          switch(type)
          {
             case 0 :
                x = val;
                break;
             case 1 :
                y = val;
                break;
             case 2 :
                newContenair.push_back(new A(x,y));
                break;
             default :
                assert(false);
          }
       };
    };
    et dans la grammaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Rule_t rule = 
    *(
       ch_p('{') >>
       int_p[std::bind1st(Reader,0)] >> 
       ch_p(',') >>
       int_p[std::bind1st(Reader,1)] >> 
       ch_p('}')[std::bind1st(Reader,2)];
    );
    C'est à dire que j'ai bien un unique foncteur, et que j'utilise bind1st pour donner un argument suplémentaire à l'operateur (). Ce dernier ce sert de cet argument pour faire un switch.

    Les inconvénients :
    • Le switch, c'est crados, il n'y a pas de raison de faire un test dynamique à cet endroit car, c'est toujours le même paramètre.
    • Le fait de devoir dériver mon foncteur de std::binary_function me déplait, car cela me force à faire des dérivations multiples, les actor étant souvent presques identiques, j'ai tendance à factoriser le code.
    • Cela ne marche pas, pour une raison que j'ai du mal à déterminer, mon compilo me reproche le fait que l'operateur () n'est pas constant :
      passing `const Reader' as `this' argument of `void Reader::operator()(int,int)' discards qualifiers
      alors qu'il le tolérait jusqu'ici.


    Toute opinion est la bienvenue.
    Merci à ceux qui ont lu.

  3. #3
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    La solution précédente étant définitivement mauvaise, j'ai finalement opté pour des adaptateurs faits maison.

    J'ai donc mon foncteur qui n'est plus un foncteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct Reader
    {
       Contenair cont;
       int x,y;
       Reader(Contenair & newContenair) : cont(newContenair)
       {
       };
       void setX(int val) {x = val;}
       void setY(int val) {y = val;}
     
       void valid(sp_iterator,sp_iterator) {cont.push_back(new A(x,y));}
    };
    et à coté, j'ai un adaptateur (que je ne pense pas réécrire à chaque fois), qui ressemble à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<typename T, void (T::* f)(int)>
    struct adapt_int
    {
       T& ancienFoncteur;
       adapt_int(T& newAF) : ancienFoncteur(newAF){};
       void operator()(int val)
       {
          (ent.*f)(val);
       }
    };
    du coup, je peux monter ma grammaire comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Contenair maListe;
    Reader monReader(maListe);
     
    Rule_t rule = 
    *(
       ch_p('{') >>
       int_p[adapt_int<Reader,&Reader::setX>(monReader)] >> 
       ch_p(',') >>
       int_p[adapt_int<Reader,&Reader::setY>(monReader)] >> 
       ch_p('}')[adapt_int<Reader,&Reader::valid>(monReader)];
    );
     
    parse(...,rule);
    Ce qui répond beaucoup mieux au cahier de charges. Ce qui était anciennement mon foncteur ne l'est plus, mais est utilisé pour le fabriquer.

    Seul inconvénient détecté pour le moment : il faut écrire tout un tas de templates adapt (selon le type d'actor), mais il y a sans doute un moyen d'y remédier.*


    Toute opinion est toujours bienvenue.

  4. #4
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Wow, c'est compliqué ce que tu fais. Il y a déjà des acteurs prédéfinis, utilise les!

    Et pourquoi est-ce que tu stockes des pointeurs vers A dans ta liste ? Utilise des A tout simplement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    std::list<A> conteneur;
    A tmp;
     
    Rule_t rule = 
    *(
       (
          ch_p('{') >>
          int_p[assign_a(tmp.x)] >> 
          ch_p(',') >>
          int_p[assign_a(tmp.y)] >> 
          ch_p('}')
       )[ push_back_a(conteneur, tmp) ]
    );

  5. #5
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Merci beaucoup pour ta réponse.

    J'avoue que ta solution est simple et efficace. Mais elle ne répond pas à ma problématique.

    La raison en est sans doute que dans un soucis de simplicité, j'ai mal exprimé ma problématique.

    Ce que j'ai à remplir, n'est pas une liste de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct A
    {
       int x,y;
    }
    Mais plutôt une liste de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class A
    {
       protected :
          int x,y;
       public :
          void setXY(int newX, int newY); 
    }
    Et je souhaite pas donner la possibilité à mon programme de se retrouver avec des objets à moitié construits (par exemple des objets ayant un x définit mais pas de y). En particulier, je ne veux pas faire de fonctions Dans ce cas, assign_a ne peut pas vraiment m'aider n'est-ce pas ?

  6. #6
    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 : 51
    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
    Je n'ai pas d'expérience pratique de spirit, mais je me demande si tu ne pourrais pas faire de fonctions setX et setY, privées, et rendre l'actor friend de ta classe.
    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.

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

Discussions similaires

  1. Philosophie rails et javascript
    Par robindelhuxley dans le forum Ruby on Rails
    Réponses: 3
    Dernier message: 15/05/2007, 11h35
  2. Réponses: 10
    Dernier message: 04/10/2006, 19h50
  3. "Philosophie" de la programmation Prolog
    Par Trap D dans le forum Prolog
    Réponses: 2
    Dernier message: 19/01/2006, 13h01
  4. Réponses: 10
    Dernier message: 03/10/2005, 15h42

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