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 :

design patern : conversion


Sujet :

C++

  1. #1
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut design patern : conversion
    Bonjour,

    à mon taf j'ai un .h qui définit des classes ou des typedef pour 3 types de nombres flottants de taille 4/8 et 10 (ça fait 9 types en tout), et 5 types de string donc certaines sont des classes template <int size> donc de taille statique.

    La plupart des opérateurs de conversion, comparaison, etc., entre ces différents types sont implémentés plus ou moins aléatoirement (le but étant que ça marche).

    Le problème c'est que régulièrement quand on code, on se retrouve avec des << ambiguous operator match >> , ou au contraire avec des << unable to convert from X to Y >>.

    Dans l'idée d'essayer de rendre tout ça un peu plus propre, j'aimerais savoir quels sont les différents design pattern permettant de résoudre le problème des conversions entre différents types ayant plus ou moins la même sémantique mais pas la même implémentation (string avec un 0 à la fin ou non, flottant de taille 8 passé en paramètre dans la pile du fpu ou dans la pile du cpu, etc..).

    - Je pense qu'un design pattern qui marche dans le cas général est :
    n'implémenter aucun opérateur de conversion de type operator= , et donc convertir explicitement dans le code avec des méthodes ToX(), ToY()
    - Quels sont les autres design pattern ?

    Merci beaucoup !

  2. #2
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Hello !

    "Design pattern" n'est pas tout à fait adapté dans notre cas, les design pattern étant des structures connues et répandues visant à répondre à un problème de programmation courant. Ton cas ne fait pas vraiment partie des cas courants... mais bon cela est un détail, passons aux choses sérieuses.

    Une petite mise au point : operator= n'est pas un opérateur de conversion mais un opérateur d'affectation. Un opérateur de conversion prend la forme de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    operator type_cible () const {
      // Implémentation
      return result;
    }
    Et il s'utilise sous la forme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     type_cible var2 = type_cible(var1);
    Voici un exemple (en C++11 mais les parties intéressantes sont valables en C++03).

    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
    #include <cstdint>
     
    namespace taf {
     
    class nombre final {
      uint8_t value_ = 0;
     
     public:
      nombre(uint8_t value) : value_(value) {}
      nombre(nombre const &) = default;
      nombre(nombre &&) = default;
      ~nombre() {}
      operator double () const { return static_cast<double>(value_); }
    };
     
    }  // namespace taf
    Si tu écris :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main() {
      taf::nombre nb1(3);
      uint32_t nb2 = 5;
      double result = nb2 + nb1;
      return 0;
    }
    Tu vas en effet obtenir un ambiguous overload for ‘operator+’ (operand types are ‘uint32_t {aka unsigned int}’ and ‘taf::nombre’).

    Tu peux du coup écrire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main() {
      taf::nombre nb1(3);
      uint32_t nb2 = 5;
      double result = nb2 + double(nb1);
      return 0;
    }
    Et là le code fonctionnera.

    Mon conseil est donc:
    - Virer les constructeurs par copie, sauf d'un type dans lui-même et la copie depuis les types builtin.
    - Virer les opérateurs d'affectation, sauf d'un type à lui même et l'affectation depuis les types builtin.
    - Fournir sur chaque type les opérateurs de conversion vers les autres en n'oubliant pas la constness.

    Idéalement, il faudrait aussi mettre en explicit les conversions rares et/ou qui font perdre de la précision. Tu peux aussi tout mettre en explicit, à toi de jauger en fonction du contexte.

    Cette opération peut éventuellement casser ta compile dans un premier temps mais elle te permettra de lever aisément toutes les ambiguités. Je suppose que tu es au fait de toutes les pertes de précision que ces conversions peuvent engendrer, je ne fais donc pas de diatribe sur ce point.
    Find me on github

  3. #3
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut
    Salut, merci beaucoup pour ta réponse détaillée.

    Mon conseil est donc:
    - Virer les constructeurs par copie, sauf d'un type dans lui-même et la copie depuis les types builtin.
    - Virer les opérateurs d'affectation, sauf d'un type à lui même et l'affectation depuis les types builtin.
    En gros si j'ai bien compris la démarche, tu conseilles de prendre l'ensemble vide comme ensemble initial de conversions implicites "cross type", et d'y ajouter progressivement quelques conversions dont on sait qu'elle ne peuvent pas introduire d’ambiguïté ?


    - Fournir sur chaque type les opérateurs de conversion vers les autres en n'oubliant pas la constness.
    avec des opérateurs de cast ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class MyString {
        char theChars[256];
        operator std::string() const { return std::string(this->theChars); }
    };
    Ça me parait cohérent comme proposition, et normalement ça devrait nécessiter uniquement de modifier les .h/.cpp des types, puisque qu'en gros si ça ne compile pas c'est qu'une conversion implicite n'est plus possible, et pour la rendre à nouveau possible il suffit d'ajouter un operator cast sur le type correspondant, sans qu'il n'y ait de risque d'ambiguïté (c'est valable dans le cas où on a bien viré tous les A::operator=(const B&) et les A::A(const B&) comme tu as précisé au début).

    Merci !

Discussions similaires

  1. repository design patern
    Par zalalus dans le forum C#
    Réponses: 1
    Dernier message: 02/07/2013, 19h29
  2. Design Patern Politique et types.
    Par Neckara dans le forum C++
    Réponses: 6
    Dernier message: 11/07/2012, 16h42
  3. [Débutant] Implémentation du design patern Singleton sous Borland C++ Builder XE
    Par otacon ghost dans le forum C++Builder
    Réponses: 2
    Dernier message: 04/08/2011, 15h21
  4. [V5] Conversion Objet Designer
    Par SODidier dans le forum Designer
    Réponses: 2
    Dernier message: 14/02/2011, 20h22
  5. [Design Patern] Observer
    Par anthyme dans le forum Général Python
    Réponses: 2
    Dernier message: 11/10/2006, 09h14

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