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 :

boost::any: classe de configuration partielle.


Sujet :

Boost C++

Vue hybride

3DArchi boost::any: classe de... 23/09/2008, 17h52
3DArchi Bon, j'ai trouvé un truc,... 24/09/2008, 15h16
alexrtz Salut, Pourquoi tu... 26/09/2008, 10h27
3DArchi Parce que je ne suis pas... 26/09/2008, 10h50
alexrtz C'est ultra-puissant comme... 26/09/2008, 12h04
Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut boost::any: classe de configuration partielle.
    Bonjour,
    Le besoin:
    Mon appli est constituée de plusieurs éléments X. J'ai une configuration pour ces X par défaut. Cette configuration contient un ensemble d'attributs de type différent contenant la valeur par défaut (cette valeur est modifiable).
    Chacun des éléments X peut utiliser soit la valeur par défaut, soit utiliser une valeur particulière. Cela doit être transparent pour X.
    Je ne souhaite pas associer chaque instance de X avec une instance de configuration pour: 1/ Eviter de créer un objet configuration si un seul paramètre change, 2/ Bénéficier d'une synchro pour les paramètres non spécialisés si la config par défaut change.

    La solution sur laquelle je risque de partir:
    Une classe CConfigurationDefaut avec une seule instance pour contenir la configuration par défaut. Cette classe contient en outre les attributs de configuration et une méthode pour y accéder.
    Une classe CConfig contenant les éléments spécialisés d'une configuration particulière. Elle contient une méthode pour accéder à un attribut, une méthode pour en changer la valeur (et alors créée la spécialisation), et une méthode de classe pour modifier la valeur par défaut. J'ai utilisé une map avec boost::any pour maintenir la liste des attributs spécialisés.
    Je souhaite n'accéder dans X qu'à l'interface de CConfig pour retrouver/positionner les valeurs des attributs sans me soucier s'il s'agit de la valeur par défaut ou d'une valeur spécialisée.

    Passons aux choses sérieuses:
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    // Enumeration des attributs:
    enum E_Attributs
    {
       E_1=1,
       E_2=2,
       E_3=3
    };
     
    // class de description des attributs:
    template<enum E_Attributs> struct CTraitTypeAttribut{};
    // spécialisation partielle pour chaque attribut:
    template<> struct CTraitTypeAttribut<E_1>{typedef int TypeAttribut;};
    template<> struct CTraitTypeAttribut<E_2>{typedef char TypeAttribut;};
    template<> struct CTraitTypeAttribut<E_3>{typedef double TypeAttribut;};
     
    // class de configuration par défaut:
    class CConfigurationDefaut
    {
    public:
       // récupération de l'instance:
       static CConfigurationDefaut&Defaut() {return m_Instance;}
     
       // récupération d'un attribut:
       template<enum E_Attributs P_Attr> typename CTraitTypeAttribut<P_Attr>::TypeAttribut& GetAttribut();
     
    private:
       CTraitTypeAttribut<E_1>::TypeAttribut P1;
       CTraitTypeAttribut<E_2>::TypeAttribut P2;
       CTraitTypeAttribut<E_3>::TypeAttribut P3;
    private:
       CConfigurationDefaut(){
          P1=12;
          P2='t';
          P3=4.56;
       }
       CConfigurationDefaut(const CConfigurationDefaut&){}
       ~CConfigurationDefaut(){}
       CConfigurationDefaut&operator=(const CConfigurationDefaut&){return *this;}
     
       static CConfigurationDefaut m_Instance;
    };
    // spécialisation partielle de l'accesseur aux attributs:
    template<> CTraitTypeAttribut<E_1>::TypeAttribut& CConfigurationDefaut::GetAttribut<E_1>(){return P1;}
    template<> CTraitTypeAttribut<E_2>::TypeAttribut& CConfigurationDefaut::GetAttribut<E_2>(){return P2;}
    template<> CTraitTypeAttribut<E_3>::TypeAttribut& CConfigurationDefaut::GetAttribut<E_3>(){return P3;}
     
    CConfigurationDefaut CConfigurationDefaut::m_Instance;
     
    // class de configuration partielle:
    class CConfig
    {
    public:
     
     
       template<enum E_Attributs P_Attribut>
       typename CTraitTypeAttribut<P_Attribut>::TypeAttribut getAttribut() const
       {
          std::map<enum E_Attributs,boost::any>::const_iterator L_itElement;
          L_itElement = m_mapAttributs.find(P_Attribut);
          if(L_itElement!=m_mapAttributs.end()){
             return boost::any_cast<typename CTraitTypeAttribut<P_Attribut>::TypeAttribut>(L_itElement->second);
          }
          return CConfigurationDefaut::Defaut().GetAttribut<P_Attribut>();
       }
     
       template<enum E_Attributs P_Attribut>
       void setAttribut(const typename CTraitTypeAttribut<P_Attribut>::TypeAttribut&P_oNouvelleValeur)
       {
          std::map<enum E_Attributs,boost::any>::iterator L_itElement;
          L_itElement = m_mapAttributs.find(P_Attribut);
          if(L_itElement==m_mapAttributs.end()){
             std::pair<std::map<enum E_Attributs,boost::any>::iterator,bool> L_eRetour;
             L_eRetour = m_mapAttributs.insert(std::pair<enum E_Attributs,boost::any>(P_Attribut,P_oNouvelleValeur));
             L_itElement = L_eRetour.first;
          }
          L_itElement->second = P_oNouvelleValeur;
       }
     
       template<enum E_Attributs P_Attribut>
       static void setAttributDefaut(const typename CTraitTypeAttribut<P_Attribut>::TypeAttribut&P_oNouvelleValeur)
       {
          CConfigurationDefaut::Defaut().GetAttribut<P_Attribut>() = P_oNouvelleValeur;
       }
     
    private:
       std::map<enum E_Attributs,boost::any> m_mapAttributs;
    };
    Un exemple d'utilisation:
    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
     
    #include <iostream>
    #include <string>
    #include <boost/any.hpp>
    #include <map>
    #include "config.hxx"
     
     
    int main(int argc, char* argv[])
    {
       CConfig L_oConfig1;
       CConfig L_oConfig2;
       std::cout<<"Config 1/E_1: "<<L_oConfig1.getAttribut<E_1>()<<std::endl;
       std::cout<<"Config 2/E_1: "<<L_oConfig2.getAttribut<E_1>()<<std::endl;
       L_oConfig2.setAttribut<E_1>(3);
       std::cout<<"Config 1/E_1: "<<L_oConfig1.getAttribut<E_1>()<<std::endl;
       std::cout<<"Config 2/E_1: "<<L_oConfig2.getAttribut<E_1>()<<std::endl;
       CConfig::setAttributDefaut<E_1>(-1);
       std::cout<<"Config 1/E_1: "<<L_oConfig1.getAttribut<E_1>()<<std::endl;
       std::cout<<"Config 2/E_1: "<<L_oConfig2.getAttribut<E_1>()<<std::endl;
     
       std::getc(stdin);
    	return 0;
    }
    La question:
    Chaque ajout d'attribut est un peu laborieux: ajout d'un enum, ajout de l'attribut, initialisation de l'attribut, spécialisation d'une classe trait, spécialisation d'une méthode d'accès.
    Quelqu'un n'aurait pas une idée plus simple?
    Ou quelqu'un aurait-il une astuce pour faciliter l'ajout d'attribut?
    Merci.

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Bon, j'ai trouvé un truc, mais c'est pas encore satisfaisant:
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    #include <iostream>
    #include <boost/any.hpp>
    #include <boost/preprocessor.hpp>
    #include <map>
     
    // definitions des attributs:
    #define SEQ_ATTRIBUTS      \
       ( (E_1,int,12)  )       \
       ( (E_2,char,'t') )      \
       ( (E_3,double,4.56) )
     
     
    /*
    ********************************************************************************
    ******************** Implementation de la classe de configuration     **********
    ********************************************************************************
    */
    // creation de l'enumeration:
    #define SEQ_AJOUT_ELEM_ENUM(r,data,elem)\
       BOOST_PP_TUPLE_ELEM(3,0,elem),
    // Enumeration des attributs:
    enum E_Attributs
    {
       BOOST_PP_SEQ_FOR_EACH(SEQ_AJOUT_ELEM_ENUM,~,SEQ_ATTRIBUTS)
    };
    #undef SEQ_AJOUT_ELEM_ENUM
     
    // classe de description des attributs:
    template<E_Attributs> struct CTraitTypeAttribut{};
    // macro pour leur specialisation
    #define D_CREER_ATTRIBUT(r,data,Attribut)\
       template<> struct CTraitTypeAttribut<BOOST_PP_TUPLE_ELEM(3,0,Attribut)>{\
          typedef BOOST_PP_TUPLE_ELEM(3,1,Attribut) TypeAttribut;\
          static const TypeAttribut Defaut;\
       };\
       const CTraitTypeAttribut<BOOST_PP_TUPLE_ELEM(3,0,Attribut)>::TypeAttribut CTraitTypeAttribut<BOOST_PP_TUPLE_ELEM(3,0,Attribut)>::Defaut  = BOOST_PP_TUPLE_ELEM(3,2,Attribut);
     
    BOOST_PP_SEQ_FOR_EACH(D_CREER_ATTRIBUT,~,SEQ_ATTRIBUTS)
    #undef D_CREER_ATTRIBUT
     
    // Macros pour preprocessor/repeat:
    #define D_NOM_ATTRIBUT(Attribut) BOOST_PP_CAT(m_,BOOST_PP_TUPLE_ELEM(3,0,Attribut))
    #define D_DECLARE_ATTRIBUT(r,data,Attribut)\
       CTraitTypeAttribut<BOOST_PP_TUPLE_ELEM(3,0,Attribut)>::TypeAttribut D_NOM_ATTRIBUT(Attribut);
    #define D_INITIALISE_ATTRIBUT(r,data,Attribut)\
       D_NOM_ATTRIBUT(Attribut) = CTraitTypeAttribut<BOOST_PP_TUPLE_ELEM(3,0,Attribut)>::Defaut;
    #define D_SPECIALISE_GETATTRIBUT(r,data,Attribut)\
       template<> CTraitTypeAttribut<BOOST_PP_TUPLE_ELEM(3,0,Attribut)>::TypeAttribut& CConfigurationDefaut::GetAttribut<BOOST_PP_TUPLE_ELEM(3,0,Attribut)>()\
          {return D_NOM_ATTRIBUT(Attribut);}
     
     
    // class de configuration par défaut:
    class CConfigurationDefaut
    {
    public:
       // récupération de l'instance:
       static CConfigurationDefaut&Defaut() {return m_Instance;}
     
       // récupération d'un attribut:
       template<E_Attributs P_Attr> typename CTraitTypeAttribut<P_Attr>::TypeAttribut& GetAttribut();
     
    private:
       // declaration des attributs:
       BOOST_PP_SEQ_FOR_EACH(D_DECLARE_ATTRIBUT,~,SEQ_ATTRIBUTS)
     
    private:
       CConfigurationDefaut(){
          // Initialisation des attributs:
          BOOST_PP_SEQ_FOR_EACH(D_INITIALISE_ATTRIBUT,~,SEQ_ATTRIBUTS)
       }
       CConfigurationDefaut(const CConfigurationDefaut&){}
       ~CConfigurationDefaut(){}
       CConfigurationDefaut&operator=(const CConfigurationDefaut&){return *this;}
     
       static CConfigurationDefaut m_Instance;
    };
    // spécialisation partielle de l'accesseur aux attributs:
    BOOST_PP_SEQ_FOR_EACH(D_SPECIALISE_GETATTRIBUT,~,SEQ_ATTRIBUTS)
     
    CConfigurationDefaut CConfigurationDefaut::m_Instance;
     
    #undef D_DECLARE_ATTRIBUT
    #undef D_INITIALISE_ATTRIBUT
    #undef D_SPECIALISE_GETATTRIBUT
     
    // class de configuration partielle:
    class CConfig
    {
    public:
     
     
       template<enum E_Attributs P_Attribut>
       typename CTraitTypeAttribut<P_Attribut>::TypeAttribut getAttribut() const
       {
          std::map<enum E_Attributs,boost::any>::const_iterator L_itElement;
          L_itElement = m_mapAttributs.find(P_Attribut);
          if(L_itElement!=m_mapAttributs.end()){
             return boost::any_cast<typename CTraitTypeAttribut<P_Attribut>::TypeAttribut>(L_itElement->second);
          }
          return CConfigurationDefaut::Defaut().GetAttribut<P_Attribut>();
       }
     
       template<enum E_Attributs P_Attribut>
       void setAttribut(const typename CTraitTypeAttribut<P_Attribut>::TypeAttribut&P_oNouvelleValeur)
       {
          std::map<enum E_Attributs,boost::any>::iterator L_itElement;
          L_itElement = m_mapAttributs.find(P_Attribut);
          if(L_itElement==m_mapAttributs.end()){
             std::pair<std::map<enum E_Attributs,boost::any>::iterator,bool> L_eRetour;
             L_eRetour = m_mapAttributs.insert(std::pair<enum E_Attributs,boost::any>(P_Attribut,P_oNouvelleValeur));
             L_itElement = L_eRetour.first;
          }
          L_itElement->second = P_oNouvelleValeur;
       }
     
       template<enum E_Attributs P_Attribut>
       static void setAttributDefaut(const typename CTraitTypeAttribut<P_Attribut>::TypeAttribut&P_oNouvelleValeur)
       {
          CConfigurationDefaut::Defaut().GetAttribut<P_Attribut>() = P_oNouvelleValeur;
       }
     
    private:
       std::map<enum E_Attributs,boost::any> m_mapAttributs;
    };
     
     
     
    int main(int argc, char* argv[])
    {
       CConfig L_oConfig1;
       CConfig L_oConfig2;
       std::cout<<"Config 1/E_1: "<<L_oConfig1.getAttribut<E_1>()<<std::endl;
       std::cout<<"Config 2/E_1: "<<L_oConfig2.getAttribut<E_1>()<<std::endl;
       L_oConfig2.setAttribut<E_1>(3);
       std::cout<<"Config 1/E_1: "<<L_oConfig1.getAttribut<E_1>()<<std::endl;
       std::cout<<"Config 2/E_1: "<<L_oConfig2.getAttribut<E_1>()<<std::endl;
       CConfig::setAttributDefaut<E_1>(-1);
       std::cout<<"Config 1/E_1: "<<L_oConfig1.getAttribut<E_1>()<<std::endl;
       std::cout<<"Config 2/E_1: "<<L_oConfig2.getAttribut<E_1>()<<std::endl;
     
       std::getc(stdin);
    	return 0;
    }
    Amélioration: je n'ai plus qu'un seul endroit pour rajouter les nouveaux attributs au niveau de #define SEQ_ATTRIBUTS !
    Moins: le code devient de moins en moins compréhensible
    Nouvel objectif: comment faire si je veux gérer des ensembles de configuration distinct pour des X et pour des Y?

  3. #3
    Membre éprouvé Avatar de alexrtz
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2003
    Messages
    639
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2003
    Messages : 639
    Par défaut
    Salut,

    Pourquoi tu n'utilises pas boost::program_options ?

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Parce que je ne suis pas encore arrivé jusqu'à ce module... Comme c'est une mauvaise réponse, je vais me plonger dans la doc.
    Merci.

  5. #5
    Membre éprouvé Avatar de alexrtz
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2003
    Messages
    639
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2003
    Messages : 639
    Par défaut
    C'est ultra-puissant comme truc

    Pour le projet sur lequel je travaille en ce moment, j'me suis fait une classe Options qui gère la config.
    Chaque classe qui a besoin d'avoir des paramètres de config s'enregistre auprès de cette classe, en lui donnant juste les paramètres par défaut, les noms et messages d'aide des options, et la variable dans laquelle mettre l'option.

    Au démarrage du programme, la classe Options regarde, pour toutes les classes enregistrées, quelles sont les options à aller chercher et s'occupe de tout

Discussions similaires

  1. Réponses: 0
    Dernier message: 30/03/2010, 13h58
  2. boost::any ou boost::variant ?
    Par vandamme dans le forum Boost
    Réponses: 4
    Dernier message: 09/04/2009, 21h32
  3. avantages de boost::any par rapport à void *
    Par vandamme dans le forum Boost
    Réponses: 2
    Dernier message: 05/03/2009, 00h46

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