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 :

conversion de valeur "compile time"


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Décembre 2006
    Messages
    96
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 96
    Par défaut conversion de valeur "compile time"
    Bonjour

    J'ai implémenté un systeme de conversions de grandeurs physiques (représentées en "double")
    Je veux que les conversions se fassent autant que possible à la compilation.

    voici l'implémentation actuelle (dans une en-tête):
    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
    class Converter {
    public:
     
        constexpr Converter(double factor, double offset) :
            factor_(factor), offset_(offset) {}
     
     
        constexpr double toHuman(double siVal) const {
            return (siVal - offset_) / factor_;
        }
     
        constexpr double toSI(double humanVal) const {
            return humanVal * factor_ + offset_;
        }
     
    private:
        double factor_;
        double offset_;
     
    };
     
     
     
    // converts to and from Pa
    static Converter pressureHPa (100, 0);
    static Converter pressurPSI (6894.75729 , 0);
     
    // converts to and from m3
    static Converter volumeL (1/1000.0, 0);
    static Converter volumeML (1/1000000.0, 0);
    static Converter volumeGal (0.00378541, 0);
     
    // converts to and from m3/s
    static Converter flowLPS (1/1000.0, 0);
    static Converter flowLPM (1/60000.0, 0);
    static Converter flowLPH (1/3600000.0, 0);
    static Converter flowCCM (1/60000000.0, 0);
    static Converter flowGPM (0.0000630901964, 0);
     
    // converts to and from °K
    static Converter tempC (1, 273.15);
    static Converter tempF (5.0/9.0, 459.67);
     
    // converts to and from s
    static Converter timeM (60, 0);
    static Converter timeH (3600, 0);
    static Converter timeD (84600, 0);
     
    // converts to and from kg
    static Converter massLb (0.453592, 0);
    static Converter massG (0.001, 0);
    des variables statiques dans un en-tête ça ne me plait pas du tout, car l'allocation est faite dans toutes les unités de traduction.
    Cependant déclarer ces variables "extern" va empecher la conversion en compiletime.

    Idéalement j'aurais fait une classe template avec factor et offset passés en paramètres et les 2 fonctions statiques, mais on ne peut apparemment pas avoir de parametres autres que des entiers (j'ai besoin de double)

    je pourrais m'inspirer de std::ratio, mais avec des valeurs comme 273.15, je suis bloqué.

    Est-ce qqun connait un astuce ?
    merci

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    En fait, je vois mal comment tu pourrais obtenir un résultat "compile time"

    Typiquement, on va lancer le convertisseur qui va nous demander:
    • l'unité d'origine
    • l'unité de destination
    • la valeur d'origine
    et le convertisseur nous indiquera alors la valeur dans l'unité de destination.

    Mais tout cela sera, j'ai presque envie de dire, d'office "dynamique", parce qu'on ne peut jamais prévoir quelle sera l'unité d'origine ni quelle sera la valeur introduite.

    La seule solution pour que ces valeurs soient définies à la compilation consisterait à modifier systématiquement le code pour indiquer l'unité de départ, l'unité de destination et la valeur à convertir, avant de compiler le tout... Tu avoueras qu'on fait mieux comme système

    Mais peut etre est-ce ce que tu souhaites réellement
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Décembre 2006
    Messages
    96
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 96
    Par défaut
    Bonjour
    merci pour ta réponse

    pour l'aspect langage, j'ai trouvé l'astuce que je cherchais: passer par une class traits. j'aurais du y penser avant (voir code ci-dessous).

    Pour l'aspect dynamique, c'est sur que si la valeur n'est pas connue à la compilation, ça va être tendu. Dans le pire des cas, la fonction est inline, et vu la grande complexité du calcul, c'est vraiment pas la mort !
    J'ai quand même pas mal de cas de figure ou j'introduis une constante litterale en paramètre.
    par exemplene devrait-il pas générer la constante 120 dans le code compilé?

    voici la nouvelle solution
    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
    template<class UnitsTraits>
    class Converter {
    public:
     
        static constexpr double factor = UnitsTraits::factor;
        static constexpr double offset = UnitsTraits::offset;
     
     
        static constexpr inline double toHuman(double siVal) {
            return siVal / factor - offset;
        }
     
        static constexpr inline double toSI(double humanVal) {
            return (humanVal + offset) * factor;
        }
     
    };
     
     
     
    #define DECL_UNIT_CONVERTER(name, fact, off) \
    struct name##_traits { \
        static constexpr double factor = fact; \
        static constexpr double offset = off; \
    }; \
    typedef Converter<name##_traits> name;
     
     
     
    // converts to and from Pa
    DECL_UNIT_CONVERTER(pressureHPa, 100.0, 0.0)
    DECL_UNIT_CONVERTER(pressurePSI, 6894.75729, 0.0)
     
    // converts to and from m3
    DECL_UNIT_CONVERTER(volumeL, 1/1000.0, 0.0)
    DECL_UNIT_CONVERTER(volumeML, 1/1000000.0, 0.0)
    DECL_UNIT_CONVERTER(volumeGal, 0.00378541, 0.0)
     
    // converts to and from m3/s
    DECL_UNIT_CONVERTER(flowLPS, 1/1000.0, 0.0)
    DECL_UNIT_CONVERTER(flowLPM, 1/60000.0, 0.0)
    DECL_UNIT_CONVERTER(flowLPH, 1/3600000.0, 0.0)
    DECL_UNIT_CONVERTER(flowCCM, 1/60000000.0, 0.0)
     
    // converts to and from °K
    DECL_UNIT_CONVERTER(tempC, 1.0, 273.15)
    DECL_UNIT_CONVERTER(tempF, 5/9.0, 459.67)
    DECL_UNIT_CONVERTER(tempR, 5/9.0, 0.0)
     
    // converts to and from s
    DECL_UNIT_CONVERTER(timeM, 60.0, 0.0)
    DECL_UNIT_CONVERTER(timeH, 3600.0, 0.0)
    DECL_UNIT_CONVERTER(timeD, 86400.0, 0.0)
     
    // converts to and from kg
    DECL_UNIT_CONVERTER(massLb, 0.453592, 0.0)
    DECL_UNIT_CONVERTER(massG, 0.001, 0.0)
     
     
    #undef DECL_UNIT_CONVERTER

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par remitbo Voir le message
    Bonjour
    merci pour ta réponse

    pour l'aspect langage, j'ai trouvé l'astuce que je cherchais: passer par une class traits. j'aurais du y penser avant (voir code ci-dessous).

    Pour l'aspect dynamique, c'est sur que si la valeur n'est pas connue à la compilation, ça va être tendu. Dans le pire des cas, la fonction est inline, et vu la grande complexité du calcul, c'est vraiment pas la mort !
    J'ai quand même pas mal de cas de figure ou j'introduis une constante litterale en paramètre.
    par exemplene devrait-il pas générer la constante 120 dans le code compilé?
    Pourquoi le devrait il tu viens de dire qu'entre l'inlining des fonctions et la grande complexité des algorithmes, ce ne serait pas la mort
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    @koala01: constexpr est là pour ca.

    @OP: Ton dernier code me semble pas mal, il doit faire le travail que tu attends. On peut faire légèrement différement, mais le principe reste le même :
    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
     
    template<class Unit> struct factor;
    template<class Unit> struct offset;
     
    template<class Unit>
    struct converter
    {
      static constexpr inline double toHuman(double from)
      { return from / factor<Unit>::value - offset<Unit>::value; }
     
      static constexpr inline double toSI(double from)
      { return (from + offset<Unit>::value) * factor<Unit>::value; }
    };
     
    #define CONVERTER_UNIT(name, factor_value, offset_value) \
    struct name {}; \
    template<> struct factor<name> \
    { static constexpr double value = factor_value; }; \
    template<> struct offset<name> \
    { static constexpr double value = offset_value; }; \
    };
     
    CONVERTER_UNIT(temp_F, 5/9.0, 459.67)
     
    converter<temp_F>::toSI(2);

  6. #6
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Décembre 2006
    Messages
    96
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 96
    Par défaut
    @Flob90:ta solution me parait plus générique, cependant je préfère garder la mienne qui est un peu moins verbeuse à l'utilisation.

    @koala01: j'aurais du préciser que:
    1: je suis seul utilisateur du code (ce n'est pas une bibliothèque, juste une petite API interne)
    2: au moment de la compilation les unités sont connues (ce n'est pas un systeme dynamique) et l'une des unités est toujours du SI. Je fais des calculs en SI pour éviter les conversions et les possibilités d'erreurs associées, mais les valeurs présentées sont dans des unités plus lisibles que les °K ou les m3/s
    3: la valeur à convertir n'est connues qu'en de rares occasions (ex valeurs par defaut).
    C'est clair que le "compile time" n'est pas un must absolu, mais je ne vois pas de raison de m'en passer quand l'occasion se présente

    Merci à tous les deux

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

Discussions similaires

  1. Interprétation des valeurs NULL et '' (double quotes)
    Par thatsallfunk dans le forum Administration
    Réponses: 2
    Dernier message: 09/01/2009, 15h21

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