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 :

boucle for et break métaprogrammation


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut boucle for et break métaprogrammation
    Bonjour à tous,

    Je voudrais écrire l'équivalent d'une boucle for avec break en méta-programmation:

    j'ai une liste de types:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #include <boost/fusion/include/vector.hpp>
    #include <boost/mpl/at.hpp>
     
    using namespace boost::fusion;
    typedef vector<int, double, std::string> mes_types;
    sur laquelle je vais appliquer un foncteur au run-time:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    struct mon_foncteur
    {
       template<typename T> T operator()(T const& src) { return src + 2; }
       template<> std::string operator()(std::string const& src) { return src + "yz"; }
    };
    je voudrais donc pouvoir itérer sur ma liste de types, appliquer mon foncteur dessus, mémoriser les résultats de l'application du foncteur et m’arrêter lorsque le résultat du foncteur rencontre une condition particulière; fonctionnellement un truc dans ce goût là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    bool function(mes_types const& types, mes_types& result)
    {
        mon_foncteur f;
        for(size_t i=0; i<result_of::size<mes_types>::type::value; ++i)
        {
            //on applique le foncteur et on récupère les résultats
            at_c<i>(result) = f(at_c<i>(types)); //problème de compilation: i est n'est pas une constante connue à la compilation
            if(check(at_c<i>(result))
                return false; //le check a échoué, on arrête la boucle
        }
        return true; //ok tout s'est bien passé
    }
    avec check une méthode qui vérifie le résultat du foncteur, par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template<typename T> bool check(T const& t)
    {
       return t%2 == 0;
    };
    template<> bool check<std::string>(std::string const& s)
    {
       return s.size()%2 == 0;
    };
    Ce code ne compile pas car il faudrait indiquer au compilateur que la boucle peut être déroulée à la compilation et qu'il n'y a donc pas de problèmes à appeler at_c<i>. Voilà je sèche un peu, je suis parti sur du boost mais si vous avez une solution en C++ "classique" je suis preneur.

    P.S. l'exemple "complet" presque compilable:
    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
     
    #include <string>
    #include <boost/fusion/include/vector.hpp>
    #include <boost/fusion/include/size.hpp>
    #include <boost/fusion/include/make_vector.hpp>
    #include <boost/mpl/at.hpp>
     
    using namespace boost::fusion;
    typedef vector<int, double, std::string> mes_types;
     
    struct mon_foncteur
    {
       template<typename T> T operator()(T const& src) { return src + 2; }
       template<> std::string operator()(std::string const& src) { return src + "yz"; }
    };
     
    template<typename T> bool check(T const& t)
    {
       return t%2 == 0;
    };
    template<> bool check<std::string>(std::string const& s)
    {
       return s.size()%2 == 0;
    };
     
    bool function(mes_types const& types, mes_types& result)
    {
        mon_foncteur f;
        for(size_t i=0; i<result_of::size<mes_types>::type::value; ++i)
        {
            at_c<i>(result) = f(at_c<i>(types));
            if(check(at_c<i>(result))
                return false; //le foncteur a echoué
        }
        return true;
    }
     
    int main()
    {
        //dans l'exemple suivant, on ne doit calculer que f(0) et f(11) et pas f("abcd")
        mes_types types(make_vector(0, 11, "abcd"));
        mes_types result;
        function(types, result);
        return 0;
    }

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Je ne connais pas très bien fusion, mais il me semble que c'est un cas typique où l'on peut utiliser fusion::for_each + fusion::zip_view.

    Edit : 3DArchi a raison, fold est plus approprié :
    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
     
    #include <string>
    #include <boost/fusion/include/vector.hpp>
    #include <boost/fusion/include/size.hpp>
    #include <boost/fusion/include/make_vector.hpp>
    #include <boost/fusion/include/zip_view.hpp>
    #include <boost/fusion/include/fold.hpp>
     
     
    using namespace boost::fusion;
    typedef vector<int, double, std::string> mes_types;
     
    struct mon_foncteur
    {
       template<typename T> 
       T operator()(T const& src) const 
       { 
          return src + 2; 
       }
       std::string operator()(std::string const& src) const 
       { 
          return src + "yz"; 
       }
    };
     
    template<typename T> 
    bool check(T const& t)
    {
       return ((int)t % 2) == 0;
    };
     
    bool check(std::string const& s)
    {
       return (s.size() % 2) == 0;
    };
     
    struct ApplyFuncAndCheck
    {
       mon_foncteur f;
       typedef bool result_type;
     
       ApplyFuncAndCheck(mon_foncteur f):f(f){}
     
       template <typename T>
       bool operator()(bool res, T& t) const
       {
          if(res == false)
          return false;
     
          at_c<1>(t) = f(at_c<0>(t));
          if(check(at_c<1>(t)) == false)
             return false; //le foncteur a echoué
          return true;
       }
    };
     
    bool function(mes_types const& types, mes_types& result)
    {
       mon_foncteur f;
       bool res = true;
     
       typedef vector<mes_types const&, mes_types&> zip_types;
       return fold(zip_view<zip_types>(zip_types(types, result)), res,  ApplyFuncAndCheck(f));
    }
     
    int main()
    {
        //dans l'exemple suivant, on ne doit calculer que f(0) et f(11) et pas f("abcd")
        mes_types types(make_vector(0, 10, "abcd"));
        mes_types result;
        function(types, result);
        return 0;
    }
    PS : J'ai supprimé les spécialisations de la fonction check et de l'opérateur() de mon_foncteur, des surcharges suffisent non ?

  3. #3
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Réponse rapide : faut faire un pli (iter_fold) il me semble

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Merci pour vos réponses.

    Par contre ça me gène un peu de ne pas pouvoir "couper" la boucle, dans mon exemple réel, l'application de mon foncteur peut être assez coûteuse et j'ai donc tout intérêt à ne pas en faire de trop.

    J'avais pensé à lever une exception lorsque le check échoue, mais je ne trouve pas cette solution très élégante et je ne me rend pas trop compte de l'incidence sur les performances (j'avais pensé à ça car dans boost.graph, ils utilisent cette technique pour les visiteurs)

    PS : Arzar effectivement, les surcharges suffisent.

    Edit: J'avais pas fait attention à ces lignes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if(res == false)
          return false;
    dans ApplyFuncAndCheck, qui permettent donc de "couper" suffisamment ma boucle (je n'aurais pas non plus des vecteur de types très longs).

    Merci

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Je vais essayer cet après midi avec boost::fusion::find_if, ils proposent une version pouvant modifier la séquence.
    J'ai regardé vite fait l'implémentation qu'ils proposent :
    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
        template <typename Pred, typename Sequence>
        inline typename 
            lazy_disable_if<
                is_const<Sequence>
              , result_of::find_if<Sequence, Pred>
            >::type
        find_if(Sequence& seq)
        {
            typedef
                detail::static_find_if<
                    typename result_of::begin<Sequence>::type
                  , typename result_of::end<Sequence>::type
                  , Pred
                >
            filter;
     
            return filter::call(fusion::begin(seq));
        }
    filter est défini dans ce fichier.
    J'ai du mal à saisir toutes les subtilités, mais j'ai l'impression qu'ils arrivent à ne pas tout dérouler et à s’arrêter dès que le prédicat est vérifié.

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

Discussions similaires

  1. Boucle for dans un script cmd
    Par nicolas.ganache dans le forum Développement
    Réponses: 4
    Dernier message: 19/07/2004, 17h07
  2. Réponses: 3
    Dernier message: 06/07/2004, 11h21
  3. [Debutant] Batch et Boucle for
    Par ludovic.fernandez dans le forum Scripts/Batch
    Réponses: 8
    Dernier message: 06/05/2004, 20h21
  4. [Swing][boucles] for, do, if .....comment faire simple?
    Par chastel dans le forum AWT/Swing
    Réponses: 7
    Dernier message: 02/05/2004, 23h49
  5. [langage] boucle "for" modification du pas
    Par K-ZimiR dans le forum Langage
    Réponses: 4
    Dernier message: 29/04/2004, 12h54

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