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 :

Boost::tuples, Templates, Nombre de paramètre


Sujet :

C++

  1. #1
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut Boost::tuples, Templates, Nombre de paramètre
    Bonjour, après avoir regardé les fonctionnalités de boost::tuples, je me suis demandé comment c'était programmé :
    Le constructeur de tuple prend un nombre de paramètres infini (contrairement aux std::pair que je vois comment programmer). Or la seule façon que je connaisse d'implémenter un nombre de paramètre indéfini est les ... que l'on récupère ensuite avec une va_liste (or je doute que se soit le cas du à l'utilisation de templates).
    Je pose donc la question :

    Comment créer un constructeur avec un nombre indéfini de paramètre et leur type indiqué grâce aux templates ?

  2. #2
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Hum un tuple ça s'implémente "aisément" avec des typelist. Sinon plus "récemment" ça se fait surtout avec le prepocessor. (plus léger etc).
    J'ai pas regardé boost::tuple mais ça doit surement être implémenté comme les autres bibliothèques qui émulent des templates variadiques (ie bind, function etc) à grand coup de prepocessor metaprogramming.
    Note qu'avec C++0x ça deviendra presque trivial avec les template variadiques supporté nativement.
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  3. #3
    Membre chevronné
    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 : 44
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    boost tuples a une amcro TUPLE_MAX_SIZE qui génére le nombre max d'elements en son sein.

    En C++0x, c'ets un bete variadics.

  4. #4
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Ce qui m'intéresse avant tout, c'est la manière qu'est programmée les fonction make_tuple car je dois créer une fonction qui marche à peu près de la même manière. Si quelqu'un pourrais me faire part de pistes pour la création d'une telle fonction... (Nombre d'argument indéterminé mais types différents mais pris en compte par les templates , appel du constructeur de tuple avec un nombre d'argument indéterminé, ...)

  5. #5
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    On t'a donné les pistes... Si t'as la chance de pouvoir choisir ton compilo et que tu te fiches plus ou moins de la portabilité : variadics template.
    Sinon tu peux te débrouiller avec une typelist (mpl::vector ou autre) si t'es pas super à l'aise avec la PMP. (y'a plus intuitif)
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  6. #6
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Les templates variadiques sont exactement ce que je voulais. Cependant, je n'ai pas trouvé le moyen de résoudre le problème majeur :

    J'ai un système de signaux. Aujourd'hui, le système de signaux est assez limité : on ne peut passer à la fonction connect qu'une fonction ayant le prototype void (*fc)(Evenement*) ou un Foncteur*
    Donc je fais un connect en faisant, un obj.connect(Event::QUIT, my_exit)
    Auquel cas, je dois créer ma propre fonction
    my_exit(Evenement* event)
    {
    exit(0);
    }

    Si possible, j'aimerais pouvoir créer un connect du type :

    obj.connect(Event::QUIT, exit (le standart), -1 (pour indiquer qu'on veut pas de Evenement* en arguement), 0 (pour indiquer que le premier argument est 0));

    ou encore obj.connect(Event::REDIM, redim, 0 (pour indiquer que l'on passera Evenement* à la position 0));

    ou encore obj.connect(ecran(endroit ou sera stocké la valeur de retour de la fonction),Event::SDL_RELOAD(exemple d'evenement imaginable), SDL_SetVideoMode, -1,800,480,32,SDL_RESIZABLE);

    etc et etc...

    Avec des templates variadiques, de telles fonctions sont - elles imaginables ?

    Ou encore faire un équivalent de boost::bind(fc,make_tuple(mes_param)) alors que fc n'est pas fait pour recevoir des tuples mais les objets constituants les tuples individuellement.

  7. #7
    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,
    J'aurais tendance à penser lambda, non ?

  8. #8
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Je n'ai jamais vu/utilisé de lambda (je ne les ai vus mentionnés que dans diverses discussions de ce forum). Je pars étudier ce que c'est et comment les utiliser. Merci

    [EDIT] Il me semble que les fonctions lambda ne sont pas ce que je souhaite car elles permettent d'appeler n fois la fonction pour chaque "objet" de la structure, mais pas d'appeler la fonction avec tous les objets de la structure (après avoir étudié la documentation de boost avec quelques problèmes).

    Si quelqu'un arrive à le faire avec des lambda, pourrait-il me l'indiquer (je persévèrerais un peu plus si je sais que c'est possible...)

  9. #9
    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
    C'était par rapport à la variabilité de tes arguments :
    (à la volée avec les lambda 0x) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    obj.connect(Event::QUIT, [](Event const&evt_){exit();});
    obj.connect(Event::REDIM,[this](Event const&evt_){this->redim(evt_);});
    obj.connect(Event::SDL_RELOAD,[&ecran](Event const&evt_){ecran = SDL_SetVideoMode(-1,800,480,32,SDL_RESIZABLE);});

  10. #10
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Après avoir lu brièvement ceci : http://en.wikipedia.org/wiki/C%2B%2B...nd_expressions, je n'ai toujours pas compris comment introduire les fonctions lambda dans ma gestion d'évènement.

    Voici le code de mon système d'évènement (il n'y a pas encore eut d'utilisation de ce système donc il se peut qu'il soit mauvais...) :

    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
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    #include <iostream>
    #include <string>
    #include <vector>
     
    using namespace std;/*Ce code n'agissant que comme un test, 
    je n'ai pas fait de .h, il n'est pas const-correcte, 
    il manque des constructeurs et etc...
    L'objectif étant de tester le système d'évènement.*/
     
    template<typename T>
    void safe_delete(T*pt)
    {
        delete pt;
        pt=NULL;
    }
     
    class Evenement
    {
        private :
            int Declancheur;
        public :
            Evenement(int D) : Declancheur(D)
            {}
            inline int get_event(){return Declancheur;}
    };
     
     
     
    class Foncteur
    {
        public :
        virtual void exec(Evenement*)=0;
    };
     
    union Function/*Ceci devrait être remplaçable avec boost.bind 
    mais le nouveau système n'utiliserait pas une classe fonction 
    puisqu'il y a les lambda*/
    {
        void (*no_param)();
        void (*param)(Evenement*);
        Foncteur*Object_Function;
    };
     
    class Callback
    {
        private :
            int Declancheur;
            Function fonction;
            char which;
        public :
            inline int get_event(){return Declancheur;}
            Callback(void(*fc)(), int Declanch)
            {
                Declancheur=Declanch;
                which=0;
                fonction.no_param=fc;
            }
            Callback(void(*fc)(Evenement*), int Declanch)
            {
                Declancheur=Declanch;
                which=1;
                fonction.param=fc;
            }
            Callback(Foncteur*fc, int Declanch)
            {
                Declancheur=Declanch;
                which=2;
                fonction.Object_Function=fc;
            }
            void operator()(Evenement*evenement)
            {
                if(which==0)
                    fonction.no_param();
                else if (which==1)
                    fonction.param(evenement);
                else if (which==2)
                    fonction.Object_Function->exec(evenement);
            }
    };
     
     
     
     
     
    class Objet
    {
        private :
            std::vector<Callback> Callbacks;
     
            //...Et autres choses.
            void handle_event(Evenement*evenement)
            {
                for(unsigned int i=0;i<Callbacks.size();i++)
                {
                    if(Callbacks[i].get_event()==evenement->get_event())
                        Callbacks[i](evenement);
                }
            }
        public :
            enum Event{QUIT,REDIM,RELOAD};
            inline void emit(Evenement*evenement)
            {
                handle_event(evenement);
                safe_delete(evenement);
            }
            inline void connect(Foncteur* fc, int Declanch)
            {
                Callbacks.push_back(Callback(fc,Declanch));
            }
            inline void connect(void(*fc)(void), int Declanch)
            {
                Callbacks.push_back(Callback(fc,Declanch));
            }
            inline void connect(void(*fc)(Evenement*), int Declencheur)
            {
                Callbacks.push_back(Callback(fc,Declencheur));
            }
    };
     
     
     
    void exit()
    {
        cout<<"exiting\n";
        exit(0);
    }
     
    class specified : public Objet
    {
        public :
            enum Event{QUIT,REDIM,SHOW,HIDE};//On utilise le masquage pour introduire de nouveaux Event.
    };
     
    int main()
    {
        specified a;
        a.connect(exit,a.HIDE);
        a.emit(new Evenement(a.HIDE));
        cout<<"error";
        return 0;
    }

  11. #11
    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,
    tu pars trop compliqué à mon avis. Tu devrais utiliser std::function (C++0x) ou boost::function (même chose en C++03) à la place des Foncteur/Function/Callback

    Et tant qu'à être en C++0x, j'ai mis un std::unordered_map mais si tu veux plusieurs gestionnaire d'évènement par type d'évènement ce serait plutôt un std::unordered_multimap. A noter que ces 2 classes sont proposées par boost en l'absence de compilateur C++0x.

    Exemple rapide à partir de ce que tu avais fait :
    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
    #include <iostream>
    #include <string>
    #include <unordered_map>
    #include <functional>
     
    class Evenement
    {
        private :
            int Declancheur;
        public :
            Evenement(int D) : Declancheur(D)
            {}
            inline int get_event()const{return Declancheur;}
    };
    namespace std
    {
        template<>
        class hash<Evenement>
        {
        public:
            typedef size_t result_type;
            typedef Evenement argument_type;
     
            result_type operator()(argument_type const&key_)const
            {
               return key_.get_event();
            }
        };
     
        template<>
        class equal_to<Evenement>
        {
            public:
          bool operator()(const Evenement& rhs_, const Evenement& lhs_) const
          { return rhs_.get_event()==lhs_.get_event(); }
        };
    }
     
     
    class Objet
    {
        private :
            typedef std::unordered_map<Evenement,std::function<void(Evenement const&)>>  evt_function_assoc_t;
           evt_function_assoc_t Callbacks;
     
            //...Et autres choses.
            void handle_event(Evenement const &evenement)
            {
                evt_function_assoc_t::const_iterator it = Callbacks.find(evenement);
                if(it!=Callbacks.end())
                {
                    it->second(evenement);
                }
            }
        public :
            enum Event{QUIT,REDIM,RELOAD};
            inline void emit(Evenement const&evenement)
            {
                handle_event(evenement);
            }
     
            inline void connect(std::function<void(Evenement const&)> callback_, int declencheur_)
            {
                Callbacks[declencheur_] = callback_;
            }
    };
     
     
     
    void exit()
    {
        std::cout<<"exiting\n";
        exit(0);
    }
     
    class specified : public Objet
    {
        public :
            enum Event{QUIT,REDIM,SHOW,HIDE};//On utilise le masquage pour introduire de nouveaux Event.
    };
     
    int main()
    {
        specified a;
        a.connect([](Evenement const&){exit();},specified::HIDE);
        a.emit(Evenement(a.HIDE));
        std::cout<<"error";
        return 0;
    }

  12. #12
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    En essayant de compiler ton code, je remarque que std::unordered_map est absent sur mon gcc (même avec l'option pour compiler en C++0x), en essayant de compiler à l'aide de boost, j'obtiens quelques erreurs. Mais passons, il me semble que ton code n'est pas plus flexible que le mien :

    typedef tr1::unordered_map<Evenement,std::function<void(Evenement const&)>> evt_function_assoc_t;
    Il me semble donc, que je ne peux connecter à n'importe quel fonction (en l'occurence SDL_SetVideoMode comme montré dans mon exemple ci-dessus).

    Il se peut, que ce que je veux faire n'est pas faisable en c++ auquel cas, je conserverais mon interface comme elle est et il faudra passer par des fonctions intermédiaires (tout comme dans Qt).

    Merci tout de même. (Bien sur si quelqu'un à une idée, qu'il en fasse part...)

  13. #13
    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
    Citation Envoyé par NoIdea Voir le message
    Il me semble donc, que je ne peux connecter à n'importe quel fonction (en l'occurence SDL_SetVideoMode comme montré dans mon exemple ci-dessus).
    Avec les lambdas tu fais un foncteur qui ne prend plus qu'un évènement en paramètre et a capturé le contexte avant. Ce serait une utilisation possible aussi avec std::bind (ou boost::bind).

  14. #14
    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
    Citation Envoyé par NoIdea Voir le message
    Si possible, j'aimerais pouvoir créer un connect du type :

    obj.connect(Event::QUIT, exit (le standart), -1 (pour indiquer qu'on veut pas de Evenement* en arguement), 0 (pour indiquer que le premier argument est 0));

    ou encore obj.connect(Event::REDIM, redim, 0 (pour indiquer que l'on passera Evenement* à la position 0));

    ou encore obj.connect(ecran(endroit ou sera stocké la valeur de retour de la fonction),Event::SDL_RELOAD(exemple d'evenement imaginable), SDL_SetVideoMode, -1,800,480,32,SDL_RESIZABLE);

    etc et etc...

    Avec des templates variadiques, de telles fonctions sont - elles imaginables ?

    Ou encore faire un équivalent de boost::bind(fc,make_tuple(mes_param)) alors que fc n'est pas fait pour recevoir des tuples mais les objets constituants les tuples individuellement.
    Hmm...
    Oui...
    C'est possible...
    Mais il faut sortir le grand jeu, la panoplie complète du "meta kung-fu holy crazy shit template metaprogrammer."

    Dans la suite du post je montre un moyen de modifier le code de 3DArchi pour autoriser une écriture similaire à celles que tu proposes, pour connecter directement une fonction de callback et ses arguments, par exemple :

    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
     
    // fonction quelconque...
    void say_hello_to(const std::string& name)
    {
       std::cout << "hello " << name << "!\n";
    }
     
    int main()
    {
       specified a;
       a.connect(specified::SHOW, &say_hello_to, "Noidea");
       a.connect(specified::QUIT, &exit, 0);
       a.emit(Evenement(a.SHOW));
       a.emit(Evenement(a.QUIT));
       std::cerr << " we shouldn't be this far." << std::endl
    }
    En fait, en C++0x, cela aurait du être assez simple. En reprenant le code de 3DArchi, il devrait suffire de :
    1) Déplacer la méthode connect en private et la renommer en connect_impl
    2) Ajouter une nouvelle méthode publique connect utilisant les templates variadiques + lambda comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template <typename Func, typename... Args>
    inline void connect(int declencheur, Func func, const Args&... args)
    {
       connect_imp( [func, args...](const Evenement&){func(args...);});
     }
    L'idée est très simple : on capture la fonction de callback et ses arguments dans la lambda.
    Malheureusement, GCC 4.5 ne se conforme pas encore au standard C++0X sur ce point car il n'accepte pas la capture d'un pack dans une lambda.

    Il faut donc émuler manuellement cette capture, en créant une fonction objet wrapper qui capturera les arguments à passer à la fonction de callback dans un tuple membre et qui lors de l'appel extraira les arguments du tuple.

    C'est pas de la tarte.

    La partie facile :
    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
     
    template <typename Func, typename... Args>
    struct Holder
    {
       Func f;
       std::tuple<Args...> arguments;
     
       Holder(Func f, const Args&... args):f(f), arguments(args...){}
     
       void operator()(const Evenement&)
      {
        apply(f, arguments);
      }
    };
     
    template <typename Func, typename... Args>
    inline void connect(int declencheur, Func func,  const Args&... args)
    {
       connect_imp(Holder<Func, Args...>(func, args...), declencheur);
    }
    Facile... sauf à ce petit détail près
    Et maintenant l'implémentation de apply, où l'on épluche le tuple récursivement : (warning template metraprogramming niveau guru en approche)
    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
     
    // apply.hpp
    #include <tuple>
     
    // Recursive case, unpack Nth argument
    template<unsigned int N>
    struct Apply_aux
    {
       template<typename Func, typename... ArgsT, typename... Args>
       static void apply(Func f, std::tuple<ArgsT...> const& t, const Args&... args)
       {
         Apply_aux<N-1>::apply(f, t, std::get<N-1>(t), args...);
       }
    };
     
    // Terminal case, call the function with unpacked arguments
    template<>
    struct Apply_aux<0>
    {
       template<typename Func, typename... ArgsT, typename... Args>
       static void apply(Func f, std::tuple<ArgsT...> const&, const Args&... args)
       {
         f(args...);
       }
    };
     
    // Actual apply function
    template<typename Func, typename... ArgsT>
    void apply(Func f, std::tuple<ArgsT...> const& t)
    {
       Apply_aux<sizeof...(ArgsT)>::apply(f, t);
     
    }
    Hé ouais.
    (Je l'ai pas inventé hein, juste trouvé sur comp.lang.c++.moderated)

    Mais passé cette difficulté, et bien c'est fait ! Le code donné plus haut dans la partie "but à atteindre" fonctionne comme prévu.

  15. #15
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Arzar, je te remercie beaucoup de ta réponse. La première solution (la supposée facile), je l'avais déjà essayer et avais reçu une liste de complainte du compilateur me disant qu'il ne comprenait pas ma variable et mes ...
    Cependant, ta seconde solution, bien que la méthode apply me parait un peu obscure me parait bien. Toutefois, étant aller sur ce site :

    http://gcc.gnu.org/projects/cxx0x.html

    pour comprendre pourquoi mon gcc 4.4 ne compilait pas les lambda, je remarque l'absence d'indication sur la non compilation des ... dans les lambda dans la version 4.5

    Ma question est donc, comment savoir quand gcc suportera les ... dans les lambda ?

  16. #16
    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
    On ne peut pas faire grand chose de plus que surveiller le bug associé à ce problème et attendre. Mais cela fait déjà 6 mois que ce bug est ouvert, donc ce n'est probablement pas facile à implémenter.

  17. #17
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Après quelques essais, j'ai finalement réussi à écrire un code :

    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
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    #include <functional>
    #include <unordered_map>
    #include <iostream>
    #include <string>
    #include <vector>
    #include "function.hpp"
    #include <queue>
    #include <boost/thread/thread.hpp>
    #include <windows.h>
    using namespace std;
     
    static int compt_call=0;
     
    class Evenement
    {
        int d;
        public :
            Evenement(){d=10;}
            int show(){std::cout<<d; return d;}
    };
     
     
    class Callback
    {
        private :
            std::function<void(Evenement*)> function;
            int id;//Information de debuggage
        public :
            Callback(std::function<void(Evenement*)> fc, int i)
            {
                function=fc;
                id=i;
            }
            void operator()(Evenement*even)
            {
                    function(even);
            }
            int get_id(){return id;}
     
    };
    template<typename T>
    class ma_file
    {
        private :
            std::queue<T> queue;
            boost::mutex m;
        public :
            void add_element(const T& el)
            {
                boost::mutex::scoped_lock lock(m);
                queue.push(el);
            }
            T delete_element()
            {
                boost::mutex::scoped_lock lock(m);
                T tmp=queue.front();
                queue.pop();
                return tmp;
            }
            operator bool()
            {
                boost::mutex::scoped_lock lock(m);
                return !queue.empty();
            }
    };
     
    class Object
    {
        private :
            ma_file<std::pair<Callback, Evenement*>>* file_thread;
            std::unordered_map<std::string,std::vector<Callback>>Callbacks;
            bool has_key(std::string key)
            {
                if(Callbacks.find(key)==Callbacks.end())
                    return false;
                return true;
            }
            void handle_event(std::string key, Evenement*even)
            {
                std::vector<Callback>&vect=Callbacks[key];
                for(unsigned int i=0;i<vect.size();i++)
                {
                    cout<<"ID : "<<vect[i].get_id()<<"\n";
                    file_thread->add_element(std::pair<Callback, Evenement*>(vect[i],even));
                }
            }
        public :
            void emit(std::string key, Evenement* even=NULL)
            {
                handle_event(key,even);
            }
            bool add_event(std::string key, Callback fc)
            {
                if(has_key(key))
                {
                    std::vector<Callback>& vect=Callbacks[key];
                    vect.push_back(fc);
                    return false;
                }
                else
                {
                    std::vector<Callback> vect(1,fc);
                    Callbacks.insert(pair<std::string,std::vector<Callback>>(key,vect));
                    return true;
                }
            }
            template<typename R, typename fc, typename ...Args>
            Callback make_callback(R& retour,fc function, Args&... param)
            {
                compt_call++;
                std::cout<<compt_call<<"\n";
                std::tuple<Args&...> my_tuple(param...);
                return Callback
                (
                    [
                        &function, &retour,my_tuple
                    ]
                    (Evenement*evens)
                        {
                            retour=call_function<R, fc, Args...>(function, my_tuple);
                        }, compt_call
                );
            }
            Object(ma_file<std::pair<Callback, Evenement*>>* mes_lancement) : file_thread(mes_lancement){};
     
    };
     
    int fc1(int& c, int& d, int& e)
    {
        std::cout<<"Valeur en entree de fonction : "<<c<<" "<<d<<" "<<e;
        c=30;
        d=3;
        e=50;
        return c;
    }
     
    class thread_argv
    {
        private :
            ma_file<std::pair<Callback, Evenement*>>*file;
            bool *exit;
        public :
            thread_argv(ma_file<std::pair<Callback, Evenement*>>* pfile, bool * ex)
            {
                file=pfile;
                *ex=false;
                exit=ex;
            }
            void operator()()
            {
                while(!(*exit) || (*file))
                {
                    while((*file))
                    {
                        std::pair<Callback, Evenement*> tmp(file->delete_element());
                        std::cout<<"ID : "<<tmp.first.get_id()<<"\n";
                        tmp.first(tmp.second);
                    }
                    Sleep(10);
                }
            }
    };
     
    class app//Classe Singleton
    {
        private :
            boost::thread *my_thread;
            ma_file<std::pair<Callback,Evenement*>>* file_thread;
            bool * pt_bool_thread;
        public :
            app()
            {
                file_thread=new ma_file<std::pair<Callback,Evenement*>>();
                pt_bool_thread=new bool;
                my_thread=new boost::thread(thread_argv(file_thread, pt_bool_thread));
            }
            ~app(){delete my_thread;delete file_thread;}
            ma_file<std::pair<Callback,Evenement*>>* get_file(){return file_thread;};
            void quit()
            {
                *pt_bool_thread=true;
                my_thread->join();
            }
     
    };
     
    int fc_2(int b)
    {
        cout<<"Sa Marche";
        return b;
    }
     
    int main()
    {
        app appli;
        Object a(appli.get_file());
     
        int b=10, c=40,d=5;
        int e=20;
        Callback tmp=a.make_callback(b, fc1, c,d,e);
        a.add_event("show",tmp);
        tmp(NULL);
        a.add_event("cout",a.make_callback(b,fc_2, b));
        tmp(NULL);
        a.emit("show");
        appli.quit();
        //a.emit("cout");
     
        std::cout<<"\nValeur après le declenchement de l'evenement : "<<b<<"\nValeur de c = "<<c<<"\n"<<d<<"\n"<<e<<"\n\n";
        return 0;
    }
    et

    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
    #ifndef FUNCTION_HPP_INCLUDED
    #define FUNCTION_HPP_INCLUDED
     
     
    #include <tuple>
     
    template<typename R, unsigned int N>
    struct __Apply_aux__
    {
       template<typename Func, typename... ArgsT, typename... Args>
       static R apply(Func f, std::tuple<ArgsT...> & t,Args&... args)
       {
         return __Apply_aux__<R,N-1>::apply(f, t, std::get<N-1>(t), args...);
       }
    };
     
    // Terminal case, call the function with unpacked arguments
    template<typename R>
    struct __Apply_aux__<R,0>
    {
       template<typename Func, typename... ArgsT, typename... Args>
       static R apply(Func f, std::tuple<ArgsT...> &, Args&... args)
       {
         return f(args...);
       }
    };
     
    template<typename R,typename T, typename ...Args>
    R call_function(T fc, const std::tuple<Args&...> & t)
    {
        return __Apply_aux__<R,sizeof...(Args)>::apply(fc, const_cast<std::tuple<Args&...> &>(t));
    }
     
    #endif // FUNCTION_HPP_INCLUDED
    toutefois, j'ai un problème :

    les 2 tmp(NULL) n'appellent pas la même fonction : le premier appelle fc1 et le 2eme fc_2. Je ne comprend pas d'où peut venir cette erreur puisque je ne manipule pas de pointeur vers un lambda mais je créé un nouveau lambda à chaque fois (du moins je crois).

    De plus, comment gérer les cas ou le type de retour de la fonction est void ?
    Pour finir, j'ai un problème quand je passe une R-Value dans make_callback, comment éviter ce problème (je me doute que c'est du au passage par référence)?

    Merci à tous.

Discussions similaires

  1. [POO] Fonction à nombre de paramètres dynamique
    Par Digimag dans le forum Langage
    Réponses: 13
    Dernier message: 14/02/2008, 22h32
  2. Réponses: 7
    Dernier message: 19/05/2006, 16h47
  3. Réponses: 11
    Dernier message: 30/03/2006, 15h39
  4. [Tableaux] Choisir le nombre de paramètres
    Par MYster dans le forum Langage
    Réponses: 1
    Dernier message: 10/11/2005, 20h27
  5. Réponses: 3
    Dernier message: 10/05/2005, 11h02

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