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 :

Différentes façons de remplacer un if else avec les templates


Sujet :

C++

  1. #1
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut Différentes façons de remplacer un if else avec les templates
    Edit: ma question ne reflétait pas le vrai problème qui est : Quels sont les différentes manières de remplacer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (condition qui peut être calculé statiquement) {
      foo();
    } else {
      bar();
    }
    par un code dont le branchement est calculé à la compilation.


    Message initial :
    Salut,

    je m'initie à la programmation générique et j'aimerais simplement afficher le min et le max d'un type.
    Je dois faire une spécialisation pour les char pour que la valeur affichée soit en int.
    J'ai essayé de faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template <class T>
    void print_min_max()
    {
       do_print_min_max<T, sizeof(T) == 1>();
    }
    mais je ne suis pas arrivé pas à écrire la fonction do_print_min_max.

    J'ai donc essayé autrement et je suis arrivé au code correct suivant :
    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 <class T, bool need_cast>
    struct cast;
     
    template <class T>
    struct cast<T, true>
    {
      typedef int type;
    };
     
    template <class T>
    struct cast<T, false>
    {
      typedef T type;
    };
     
    template <class T>
    struct cast_helper
    {
      typedef typename cast<T, sizeof(T) == 1>::type type;
    };
     
    template <class T>
    void print_min_max()
    {
      typedef typename cast_helper<T>::type type;
      std::cout << typeid(T).name() << " : min = "
                    << static_cast<type>(std::numeric_limits<T>::min())
                    << ", max = "
                    << static_cast<type>(std::numeric_limits<T>::max())
                    << std::endl;
    }
    Par contre, est-ce qu'il possible de simplifier ce code en utilisant boost traits ou mpl ?
    En outre, je serais très intéressé de savoir s'il est possible d'écrire la fonction (ou peut-être une classe) do_print_min_max.

    Merci.

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <class T>
    void print_min_max()
    {
       if (sizeof(T) == 1)
          do_print_min_max<T, int>();
       else
          do_print_min_max<T, T>();
    }

  3. #3
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut Différentes façons de remplacer un if else avec les templates
    Citation Envoyé par Sylvain Togni Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <class T>
    void print_min_max()
    {
       if (sizeof(T) == 1)
          do_print_min_max<T, int>();
       else
          do_print_min_max<T, T>();
    }
    Oui c'est possible, mais c'est dynamique.

    Donc en fait j'aimerais savoir qu'elles sont les différentes manières de remplacer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (condition qui est calculé statiquement) {
      foo();
    } else {
      bar();
    }
    par un code évaluer à la compilation.

    Le code que j'ai écrit dans mon 1er message est une manière.
    Je peux également faire :

    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
     
    template <class T, bool needCast>
    struct do_print_min_max;
     
    template <class T>
    struct do_print_min_max<T, true>
    {
      void operator()()
      {
        std::cout << "min = "
                  << static_cast<int>(std::numeric_limits<T>::min())
                  << ", max = "
                  << static_cast<int>(std::numeric_limits<T>::max())
                  << std::endl;
      }
    };
     
    template <class T>
    struct do_print_min_max<T, false>
    {
      void operator()()
      {
        std::cout << "min = "
                  << std::numeric_limits<T>::min()
                  << ", max = "
                  << std::numeric_limits<T>::max()
                  << std::endl;
      }
    };
     
    template <class T>
    void print_size_of_2()
    {
      do_print<T, sizeof(T) == 1>();
    }
    Je préfère la première méthode (cf premier message) qui permet moins de duplication de code.
    Si vous avez d'autres manières de faire je suis preneur.

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

    Informations professionnelles :
    Activité : aucun

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

    Si l'élément à tester peut être considéré comme une constante connue à la compilation (comme c'est le cas pour sizeof, par exemple), tu peux utiliser l'opérateur ternaire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <typename T>
    void foo(/*...*/)
    {
        condition ? execution_si_vrai : execution_si_faux;
    }
    car le compilateur est capable d'évaluer cet opérateur au moment de la compilation
    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 émérite

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Par défaut
    Citation Envoyé par b Oo Voir le message
    Donc en fait j'aimerais savoir qu'elles sont les différentes manières de remplacer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (condition qui est calculé statiquement) {
      foo();
    } else {
      bar();
    }
    par un code évaluer à la compilation.
    D'abord certes le code avec un if est en théorie dynamique, mais en pratique je ne connais aucun compilateur qui n'optimiserai pas un if (true) ou un if (false). D'ailleurs existe-t-il une telle instruction en assembleur ?

    Sinon une autre solution (pas forcement la meilleure)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #if condition qui est calculé statiquement
      foo();
    #else
      bar();
    #endif

  6. #6
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Citation Envoyé par Sylvain Togni Voir le message
    D'abord certes le code avec un if est en théorie dynamique, mais en pratique je ne connais aucun compilateur qui n'optimiserai pas un if (true) ou un if (false).
    Oui c'est vrai.
    En outre, avec l'option -Wunreachable-code, g++ va émettre un warning du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #In function ‘void print_size_of() [with T = long unsigned int]’:
    print_size_of_type.cpp:19: warning: will never be executed
    Ta solution est correcte mais je n'aime pas trop.
    Cela revient pour moi, en exagérant, à utiliser des effets de bord dans un langage fonctionnel pur.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    C'est justement là qu'intervient l'opérateur ternaire "?"...

    Non seulement, le compilateur est parfaitement capable d'évaluer la condition à la compilation, mais, de plus, l'opérateur ternaire ne brise absolument pas le flux d'exécution...

    Un "if else" normal nous forcerait à écrire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void foo(int i)
    {
        //i est le nombre d'euros que j'ai en poche
        cout<<"j'ai "<<i;
        if(i==0 || i==1)
            cout<<"euro";
        else
            cout<<" euros"
        cout<<" en poche";
    }
    alors que l'opérateur ternaire nous permet l'écriture d'un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void foo(int i)
    {
        cout<<"j'ai "<<i<<(i==0 || i==1 ? " euro":" euros")<<" en poche";
    }
    Comme vous le constatez, je n'ai pas du mettre fin à mon instruction d'affichage

    Le principe peut parfaitement s'appliquer à tout et n'importe quoi...
    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

  8. #8
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Citation Envoyé par koala01 Voir le message
    C'est justement là qu'intervient l'opérateur ternaire "?"...

    Non seulement, le compilateur est parfaitement capable d'évaluer la condition à la compilation, mais, de plus, l'opérateur ternaire ne brise absolument pas le flux d'exécution...
    Ok je vois ce que tu veux dire. Ce n'est pas interprété par le compilateur comme un branchement (au sens if/else) et donc il n'y aura pas de warning.
    Pour moi l'opérateur ternaire était seulement un raccourci de if/else avec une seule instruction.

    Merci.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Pour moi l'opérateur ternaire était seulement un raccourci de if/else avec une seule instruction.
    Hé bien non... l'opérateur ternaire est réellement considéré comme une opération atomique...
    Merci.
    Mais de rien...
    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

  10. #10
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    Citation Envoyé par Sylvain Togni Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <class T>
    void print_min_max()
    {
       if (sizeof(T) == 1)
          do_print_min_max<T, int>();
       else
          do_print_min_max<T, T>();
    }
    ca suffit largement. Comme sizeof(T) est evalué à la compil, le test l'ai aussi. le compilo detecte un branchement toujour svrai et elimine le if. LE code resultant est celui de la bonne branche.

  11. #11
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Est-ce qu'on peut résumer que n'importe quel test qui peut être résolu à la compilation le sera? (avec MSVC et GCC par exemple comme c'est les plus communs)

    Ou est-ce qu'il faut des conditions particulières comme dans les réponses données ici (template, operateur ternaire) ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Je crois que seul l'opérateur ternaire est garanti fonctionner à la compilation...

    Si l'on en juge par le seul comportement des constructeur, par exemple, un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MaClass::MaClass(int i):membre1(if(i==0) si_vrai; else si_faux)
    {
    }
    sera refusé, alors qu'u code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaClass::MaClass(int i):membre1(i==0? si_vrai : si_faux){}
    sera parfaitement admis.

    De plus, il me semble, au niveau de fonction / classes template, avoir bien plus souvent utiliser l'opérateur ternaire lorsqu'il était clair que l'évaluation se fait à la compilation que le couple if else.

    Mais bon, je n'ai pas vérifié (suffisamment récemment pour m'en souvenir, du moins) dans la norme ce qu'il en est 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

  13. #13
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 545
    Par défaut
    un compilateur digne de ce nom (genre par la toute première version du compilateur qu'on écrira soi même) remplacera les expressions ne contenant que des constantes par leur valeur, et traitera les conditionnelles dont le test est une constante ou une expression n'ayant que des constantes.
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  14. #14
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 545
    Par défaut
    Citation Envoyé par koala01 Voir le message
    un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MaClass::MaClass(int i):membre1(if(i==0) si_vrai; else si_faux)
    {
    }
    sera refusé
    heureusement, car if else n'est pas une expression

    un moment de fatigue ?
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  15. #15
    screetch
    Invité(e)
    Par défaut
    si le but est de detecter char et uniquement char, sizeof(T) est un moyen un peu detourné et tiré par les cheveux

    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
    template <class T>
    struct cast
    {
      typedef T type;
    };
     
    template <>
    struct cast<char>
    {
      typedef int type;
    };
     
    template <class T>
    void print_min_max()
    {
      typedef typename cast<T>::type type;
      std::cout << typeid(T).name() << " : min = "
                    << static_cast<type>(std::numeric_limits<T>::min())
                    << ", max = "
                    << static_cast<type>(std::numeric_limits<T>::max())
                    << std::endl;
    }
    un code avec le sizeof et qui fonctionne aussi :

    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< typename T, bool cast = (sizeof(T) == 1) >
    struct cast;
     
    template< typename T>
    struct cast<T, true>
    {
    typedef int type;
    };
     
    template< typename T>
    struct cast<T, false>
    {
    typedef T type;
    };
     
    template <class T>
    void print_min_max()
    {
      typedef typename cast<T>::type type;
      std::cout << typeid(T).name() << " : min = "
                    << static_cast<type>(std::numeric_limits<T>::min())
                    << ", max = "
                    << static_cast<type>(std::numeric_limits<T>::max())
                    << std::endl;
    }
    une structure intermediaire en moins.
    l'avantage du deuxieme c'est qu'on peut meme forcer le cast.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Citation Envoyé par bruno_pages Voir le message
    heureusement, car if else n'est pas une expression

    un moment de fatigue ?
    plutôt la preuve par l'absurde
    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

  17. #17
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par bruno_pages Voir le message
    un compilateur digne de ce nom (genre par la toute première version du compilateur qu'on écrira soi même) remplacera les expressions ne contenant que des constantes par leur valeur, et traitera les conditionnelles dont le test est une constante ou une expression n'ayant que des constantes.
    Tu vas même avoir du mal à faire un compilateur C ou C++ qui n'évalue pas les expressions entières constantes à la compilation: il le faut pour les tailles des tableaux, les valeurs des enum, les paramètres templates et les conditions du préprocesseur. Ne pas utiliser ce code dans les autres contextes ne devrait pas être compliqué.

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

Discussions similaires

  1. wpf: probleme avec les templates
    Par mk.wassim dans le forum Windows Presentation Foundation
    Réponses: 3
    Dernier message: 18/03/2009, 17h54
  2. [Smarty] Debut avec les templates
    Par Arnich dans le forum Bibliothèques et frameworks
    Réponses: 2
    Dernier message: 22/11/2007, 18h35
  3. probleme avec les templates d'un formview
    Par devdotnet dans le forum ASP.NET
    Réponses: 2
    Dernier message: 01/11/2007, 09h32
  4. Erreur de link avec les templates
    Par suiss007 dans le forum C++
    Réponses: 6
    Dernier message: 04/01/2007, 11h09
  5. Probleme avec les templates
    Par TeC_MaN dans le forum C++
    Réponses: 2
    Dernier message: 08/01/2006, 14h53

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