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

C++ Discussion :

héritage, template et générateur de code.


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut héritage, template et générateur de code.
    Boujour à tous

    Je me retrouve avec un problème quelque peu tordu.
    Dans mon équipe, nous avons un générateur de code, qui prend une description de format de fichiers CSV en entrée.

    L'idée, c'est d'abbréger fortement le temps d'écriture des validations des données, tout en offrant assez de souplesse à l'usage.
    L'une de mes contraintes, c'est que ni C++11 ni Boost ne sont autorisés (j'ai dû récupérer optional lite pour avoir un optional correct)

    Le code généré devrait ressembler à ceci:
    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
    class Bidule {
    public:
       typedef types::string::value_type champ1_type;
       typedef types::optional_integer::value_type champ2_type;
    private:
       champ1_type champ1;
       champ2_type champ2;
    public:
       Bidule(champ1_type const& champ1, champ2_type const& champ2) : 
          champ1(champ1),
          champ2(champ2)
       {}
     
       champ1_type const& getChamp1() const {return champ1;}
       champ1_type      & getChamp1() {return champ1;}
     
       champ2_type const& getChamp2() const {return champ2;}
       champ2_type      & getChamp2() {return champ2;}
    };
     
    class Bidule_format {
    private:
       types::string  champ1;
       types::decimal champ2;
    public:
    //les constructeurs des types permettent les réglages de validations en lecture et écriture
       Bidule_format() : champ1(8), champ2(4) {}
     
       //produce a value from internal state
       Bidule operator()() const { return Bidule( champ1(), champ2() ); }
     
       Bidule_format& clear() {
          champ1.clear();
          champ2.clear();
          return *this;
       }
     
       //set internal state according to value, and return itself
       Bidule_format & operator()(Bidule const& source) {
          champ1(source.getChamp1());
          champ2(source.getChamp2());
          return *this;
       }
     
       Bidule_format & from(std::istream& stream) {
          stream >> champ1 >> champ2;
          return *this;
       }
       Bidule_format const& into(std::ostream& stream) const {
          stream << champ1 << champ2;
          return *this;
       }
    };
    Au passage, j'aimerai bien trouver un moyen d'écrire de partager la définition de type entre Bidule et Bidule_format...
    sauf que la prédéclaration de Bidule n'est pas suffisante pour Bidule_format::operator()(), et que Bidule utiliserait Bidule_format::champ1_type::value_type


    Il s'agit donc d'écrire dans une bibliothèque tout le code qui ne changerait pas d'une description à l'autre.
    Et c'est là que mes soucis commencent.

    J'ai une classe extractor qui me sert de base pour les différents types.
    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
    class extractor_base {
    public:
       virtual ~extractor() {}
     
       virtual void from(std::istream & stream) = 0;
       virtual void into(std::ostream & stream) const = 0;
       virtual void clear() =0;
    };
     
    inline std::istream& operator>> (std::istream& stream, extractor_base & extractor) {
       extractor.from(stream);
       return stream;
    }
     
    inline std::ostream& operator<<(std::ostream& stream, extractor_base const & extractor) {
       extractor.into(stream);
       return stream;
    }
     
    template <typename T, bool optional = false>
    class extractor : public extractor_base{
    public:
       typedef T concrete_type;
       typedef typename option_type<T, optional>::value_type value_type;//std::optional<T> ou T, selon que optional soit vrai ou non
    private:
       value_type v;   
    protected:
       explicit extractor() {}
       explicit extractor(value_type const& v) : v(v) {}
    public:
       virtual ~extractor() {}
     
       value_type const& operator() () const {return v;}
       value_type      & operator() ()       {return v;}
     
       void operator() (value_type const& value) {v = value;}
     
       virtual void clear() {v=value_type();}
    };
    types::integer, types::optional_string, etc sont héritières de extractor.

    Sauf que j'ai deux mutualisations possibles, que je n'arrive pas à écrire correctement:
    D'un coté, integer et optional_integer ont le même format.
    De l'autre, les optional ont la même interaction avec les flux, et les autres types en partage une autre

    Typiquement, je peux écrire
    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
    template <typename Value>
    class strict_type : public extractor<Value, false> {
    public:
       virtual void from(std::istream & stream) {
          set(extract(next(stream)));
       }
     
       virtual void into(std::ostream & stream) const {
          stream << format(get()) << delimiter();
       }
    };
     
    template <typename Value>
    class optional_type : public extractor<Value, true> {
    public:
       virtual void from(std::istream & stream) {
          std::string token = next(stream);
          if (empty(token)) {
             set(optional::none);
          } else {
             set(extract(token));
          }
       }
     
       virtual void into(std::ostream & stream) const {
          if (get()) {
             stream << format(*get());
          }
          stream << delimiter();
       }
    };
    Sauf que la dedans, format() et extract() sont liées au types (les memes fonctions pour integer et optional_integer)

    Et c'est la que je suis un peu perdu.
    Comment continueriez-vous cette architecture?

    J'ai au moins une contrainte sur le choix: scientific et decimal sont deux types ayant des formats différents, mais utilisant double comme type concret.
    C'est ce qui m'a poussé jusque là à ne pas partir sur des spécialisations.

    Je peux faire pas mal de chaos la dedans, les fonctions de formatage sont des fonctions libres (récupérées pour le moment).

  2. #2
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Visiblement, ma question ne vous inspire pas trop

    J'ai trouvé une solution à mes questions:
    Il "suffit" de passer par des classes intermédiaires.
    Ici, j'ai pris optional<Format> et required<Format>. Elles contiennent un champ du type du format, sont des extracteurs.
    Ainsi, mon optional_integer est devenu un typedef de optional<integer>.

    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
    template <typename T, bool optional = false>
    class extractor {
    public:
       typedef T concrete_type;
       typedef typename option_type<T, optional>::value_type value_type;
    private:
       value_type v;   
    protected:
       explicit extractor() {}
       explicit extractor(value_type const& value) : v(value) {}
    public:
       virtual ~extractor() {}
     
       virtual void from(std::istream & stream) = 0;
       virtual void into(std::ostream & stream) const = 0;
     
       value_type const& operator() () const {return v;}
       value_type      & operator() ()       {return v;}
     
       value_type const& get() const {return v;}
       void set() (value_type const& value) {v = value;}
     
       virtual void clear() {v=value_type();}
    };
     
    //sets the internal value of the extractor.
    template <typename T, bool optional>
    inline std::istream& operator>> (std::istream& stream, extractor<T, optional> & extractor) {
       extractor.from(stream);
       return stream;
    }
     
    //outputs the internal value of the extractor.
    template <typename T, bool optional>
    inline std::ostream& operator<<(std::ostream& stream, extractor<T, optional> const & extractor) {
       extractor.into(stream);
       return stream;
    }
     
    template<typename Format>
    class required : public extractor<typename Format::type, false> {
    private:
       Format format;
    public:
       required(Format const& format) : extractor(), format(format) {}
     
       virtual void from(std::istream & stream) {
          set( format.extract(next(stream)) );
       }
     
       virtual void into(std::ostream & stream) const {
          stream << format.format(get()) << delimiter();
       }
    };
     
    template<typename Format>
    class optional : public extractor<typename Format::value_type, true> {
    private:
       Format format;
    public:
       optional(Format const& format) : extractor(), format(format) {}
     
       virtual void from(std::istream & stream) {
          std::string token;
          std::getline(stream, token, ';');
          if (my::empty(token)) {
             set(nonstd::nullopt());
          } else {
             set(format.extract(token));
          }
       }
     
       virtual void into(std::ostream & stream) const {
          if (get()) {
             stream << format.format(*get());
          }
       }
    };
     
    class integer {
    public:
       typedef long value_type;
       typedef std::string::size_type size_type;
     
    private:
       size_type digits;
     
    public:
       integer(size_type digits) : digits(digits) {}
     
       std::string format(value_type valeur) const { ...  }
       value_type extract(std::string const& token) const { ... }
    };
    Il me reste toujours ma question au passage, mais le sujet principal est clos.

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

Discussions similaires

  1. [andromda]Infos sur andromda, générateur de code JAVA
    Par ugos dans le forum EDI et Outils pour Java
    Réponses: 5
    Dernier message: 08/09/2009, 15h30
  2. [Sunopsis] et les ETL générateur de code ?
    Par manuaccess10 dans le forum ODI (ex-Sunopsis)
    Réponses: 5
    Dernier message: 20/12/2006, 12h54
  3. Générateur de code
    Par jojo. dans le forum Mode d'emploi & aide aux nouveaux
    Réponses: 1
    Dernier message: 21/04/2006, 10h24
  4. Réponses: 4
    Dernier message: 21/02/2006, 19h45
  5. [Info][API]Générateur de code
    Par Archangelo dans le forum API standards et tierces
    Réponses: 6
    Dernier message: 24/07/2005, 14h59

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