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 :

problème C++1x et <functional>


Sujet :

Langage C++

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 11
    Par défaut problème C++1x et <functional>
    Bonjours !...

    Je bloque sur un code C++1x pourtant très bête, et sur une erreur de compilation incompréhensible :

    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
    #include <functional>
    using namespace std;
     
    class Event
    {
          public:
                Event & operator += (function < void (const Event &) > &_trigger)
                {
                       ;
                }
    };
     
    void onClick (const Event &e)
    {
          ;
    }
     
    int main ()
    {
          Event e;
          e += onClick;
    }
    j'ai largement éclairci le code je pense qu'il s'explique de lui-même. Comme vous pouvez le voir j'utilise les functional qui sont la partie C++1x du code. Ce code plante avec cette erreur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    In function ‘int main()’:
    21: error: no match foroperator+=’ in ‘e += onClick’
    7: note: candidates are: void Event::operator+=(std::function<void(const Event&)>&)
    === Build finished: 1 errors, 0 warnings ===
    En revanche en utilisant les pointeurs de fonctions classiques, ça fonctionne :

    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
    #include <functional>
    using namespace std;
     
    class Event
    {
          public:
                void operator += (void(* _trigger) (const Event &))
                {
                       ;
                }
    };
     
    void onClick (const Event &e)
    {
          ;
    }
     
    int main ()
    {
          Event e;
          e += onClick;
    }
    je ne comprend pas le rapport entre l'utilisation des functional et le message de l'erreur

    Mon but est évidemment d'utiliser les functional et non pas de rester sur les pointeurs de fonction classiques ! Qu'est ce que je dois corriger pour que mon code compile ??

  2. #2
    zul
    zul est déconnecté
    Membre chevronné Avatar de zul
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    498
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 498
    Par défaut
    Passe ta function<> par copie. Ici tu essaye de créer une function<> temporaire par référence ce qui est interdit (tu peux soit la passer par copie ou par const ref, mais il est recommandé de passer les foncteurs par copie)).

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 11
    Par défaut
    Effectivement, ça marche avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Event & operator += (const function < void (const Event &) > &_trigger)
    Mais pourquoi ce n'est pas conseillé ? Ou plutôt pourquoi est-il conseillé de passer les foncteurs par copie ? Je veux dire que cela économise de la mémoire et du cpu de passer par des ref (certes ce n'est pas critique ici mais bon)

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 11
    Par défaut
    Re bonjour, c'est encore moi. Après de long mois d’abstinence je suis revenu au combat sur le terrain de std::functionnal.
    Et là, je rencontre un autre problème: Je ne sais pas comment utiliser un std::fonction<> sur une fonction membre, une méthode quoi. J'imagine que le problème vient de ce que je ne passe pas le pointeur sur l'objet, mais... je ne vois pas comment je dois faire ça ! mes recherches ne m'aident vraiment j'en reviens et ... impossible de trouver un exemple ou de comprendre ce qu'est mem_fun et autres

    mon 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
    class Event
    {
          public:
                Event & operator += (const function < void (const Event &) > &func) {
     
     
                       return *this;
                }
    };
     
    class Form
    {
          public:
                Form ()
                {
                      eClick += onClick;
                }
     
                void onClick (const Event &e) {
                      ;
                }
     
                Event eClick;
    };
     
    int main ()
    {
          ;
    }
    les insultes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /home/charles/Projects/app/c++/bin/test/src/app.cpp||In constructor ‘Form::Form()’:|
    /home/charles/Projects/app/c++/bin/test/src/app.cpp|32|error: no match foroperator+=’ in ‘((Form*)this)->Form::eClick += ((Form*)this)->Form::onClick’|
    /home/charles/Projects/app/c++/bin/test/src/app.cpp|20|note: candidates are: Event& Event::operator+=(const std::function<void(const Event&)>&)|
    ||=== Build finished: 1 errors, 0 warnings ===|

  5. #5
    Invité
    Invité(e)
    Par défaut
    onClick n'a pas pour type void (const Event &) mais void (Form:: )(const Event &). Pour résoudre se problème soit :
    • tu n'utilises aucun membres de Form dans onClick, alors tu trasform onClick en fonction global(ou static)
    • tu utilises des membres de Form, alors tu attache this à onClick grace à std::bind
    Dernière modification par koala01 ; 28/11/2010 à 23h27. Motif: ajout d'un espace pour éviter l'évaluation d'un smiley

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 11
    Par défaut
    mmh voici ce que j'obtient en changeant le type

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    /home/charles/Projects/app/c++/bin/test/src/app.cpp|25|error: a call to a constructor cannot appear in a constant-expression|
    /home/charles/Projects/app/c++/bin/test/src/app.cpp|25|error: template argument 1 is invalid|
    /home/charles/Projects/app/c++/bin/test/src/app.cpp||In constructor ‘Form::Form()’:|
    /home/charles/Projects/app/c++/bin/test/src/app.cpp|37|error: no match foroperator+=’ in ‘((Form*)this)->Form::eClick += ((Form*)this)->Form::onClick’|
    ||=== Build finished: 3 errors, 0 warnings ===|
    Où la ligne 25 est la suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                Event & operator += (const function < void (Form::)(const Event &) > &func) {

  7. #7
    Invité
    Invité(e)
    Par défaut
    Tu peux essayer de remplacer ta ligne par celle-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Event & operator += (const function < voie (Form&,const Event &) > &func)
    Si je ne me trompe pas, la classe std::function est inspirée de celle fournie par boost. Celle ci est un peu plus documentée, tu peux aller voir par ici pour commencer.
    Dernière modification par Invité ; 10/12/2010 à 18h45.

  8. #8
    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
    Par défaut
    Salut,
    std::bind est ton ami :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Form::Form ()
    {
       eClick += std::bind(&Form::onClick,this,std::placeholders::_1);
    }
    Mais puisque tu t'aventures en terre C++0x, alors un grand cri : lambda !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Form::Form ()
    {
       eClick += [this](const Event&e_){onClick(e_);};
    }

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 11
    Par défaut
    Après quelques mois d'empêchements, je reviens à la chasse :p
    J'ai bien utilisé bind avec succès, ainsi que les fonctions lambda par ailleurs, grâce à gcc 4.5

    Maintenant j'ai un souci (majeur) et je soupçonne que cela vienne du template.
    J'ai une méthode template que voici:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template <class C> void operator , (void(C::*m)()) {
            // (mObject<C>()->*m)();
            std::function <void(C*)> func = m;
            m(mObject<C>());
    }
    mObject est une méthode template qui stocke un pointeur sur un object (de type "C") dans une variable static et la renvoie, c'est la seule manière que j'ai trouvé de stocker ce pointeur entre deux appels de méthodes puisqu'il est impossible d'avoir un "attribut template", et je ne veux pas que la classe soit elle-même template.

    la ligne en commentaire fonctionne très bien. Les deux suivantes aussi et c'est là où je voudrais agir: j'aimerais pouvoir "binder" le paramètre pointeur pour pouvoir stocker le tout dans un object de type std::function<void()>. Le but étant de se libérer de devoir donner le type "C" en paramètre template, puisque l'appel doit se faire depuis une fonction non template.

    Ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    std::function<void(C*)> func;
    std::bind1st(func, mObject<C>());
    Ne compile pas et je ne comprend pas pourquoi.

    Est-ce que cela est possible d'une façon ou d'une autre ?

  10. #10
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Bonsoir,
    Comment est défini mObject ? Je ne comprends pas son utilisation dans ton code.

    Au cas où, un rappel sur l'utilisation usuelle de std::function en conjonction avec std::bind :
    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
     
    #include <functional>
    #include <iostream>
     
    struct C
    {
       void func() const
       {
          std::cout << "func" << std::endl;
       }
    };
     
    void execute(std::function<void()> f)
    {
       // aucune mention de "C" ici
       f();
    }
     
    int main()
    {
       C c;
     
       // bind avec une copie de c
       std::function<void()> f1 = std::bind(&C::func, c); 
       std::function<void()> f2 = [c]{ c.func(); };
       execute(f1);
       execute(f2);
     
       // bind par référence (durée de vie de c à surveiller)
       std::function<void()> fref1 = std::bind(&C::func, std::ref(c)); 
       std::function<void()> fref2 = [&c]{ c.func(); };
       execute(fref1);
       execute(fref2);
    }
    Utilisé comme ceci, il n'y a plus besoin de pointeur de fonction membre explicite, la machinerie interne de bind+function s'en charge.

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 11
    Par défaut
    Salut et merci pour ta réponse !

    Voici mon code (je suis toujours en train d'essayer d'implémenter une machinerie perso pour gérer les évènements !)

    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
     
          class Trigger {
                private:
                      std::function <void()> Handler;
                      // stocke le pointeur sur l'objet
                      template <class C> inline C* mObject (C* o = nullptr) const throw() {
                            static C* p;
                            if( o ) p = o;
                            return p;
                      }
                public:
                      // sauvegarder le pointeur sur l'objet avant sauvegarde de la méthode
                      template <class C> Trigger& operator = (C* o) throw() { // Method (object)
                            mObject(o);
                            return *this;
                      }
                      // sauvegarder la méthode
                      template <class C> void operator , (void(C::*m)()) { // Method (func)
                            //
                            // ici je voudrais stocket un bond de l'objet+m dans Handler...
                            // et en fait ça marche !
                            //
                            Handler = std::bind(m, mObject<C>());
                      }
                      // déclencher l'évènement, càd appeler la fonction liée
                      void doLaunch () {
                            // ... pour pouvoir l'appeler ici
                            Handler();
                      }
          };
    class Class {
          public:
                void onGen () {
                      cout << "Event handled : Class::onGen" << endl;
                }
    };
    int main () {
     
          Trigger eGen;
          Class* o = new Class();
          eGen = o, &Class::onGen;
          eGen.doLaunch();
    }
    le problème c'est que

    Euh

    Hallelujah ! j'utilisais std::bind1st et avec std::bind ça marche ... donc le code au dessus fonctionne !!

    Un grand merci

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

Discussions similaires

  1. Problème entre Simulink et Matlab Function
    Par Océane88 dans le forum Simulink
    Réponses: 3
    Dernier message: 16/12/2014, 15h28
  2. Réponses: 1
    Dernier message: 11/01/2014, 19h57
  3. Problème passage de GtkFileFIlter à une function callback
    Par Spitfire 95 dans le forum GTK+ avec C & C++
    Réponses: 0
    Dernier message: 11/05/2012, 08h20
  4. [PHP 5.2] Problème : Call to a member function on a non-object
    Par Docteur_Hareng dans le forum Langage
    Réponses: 4
    Dernier message: 10/07/2009, 10h50
  5. Réponses: 8
    Dernier message: 10/04/2009, 14h46

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