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 :

pointeur de fonction en paramètre d'une fonction


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 45
    Points : 25
    Points
    25
    Par défaut pointeur de fonction en paramètre d'une fonction
    Bonjour à tous, je tente de mettre en place un menu de debug pour une application graphique, qui me permettrait d'afficher et de modifier au runtime la valeur de variables/membres de classes ayant été ajoutés à ce menu de debug. A cette fin, j'ai développé le code ci dessous, dans un premier temps ne prenant en charge que des variables de type float (j'ai bien essayé de passer par des templates, mais j'ai été confronté à pleins de soucis, j'ai lâché l'affaire pour le moment, c'est un autre soucis de toute façon !). Je dois notamment stocker des pointeurs vers les accesseurs de la variable à surveiller.

    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
     
     
     
    typedef void (*setterptrFloat)(float);
    typedef void (*setterptrInt)(int); //pour plus tard
    typedef void (*setterptrUint)(uint); //pour plus tard
    typedef void (*setterptrBool)(bool); //pour plus tard
     
    typedef float (*getterptrFloat)(void);
    typedef int (*getterptrInt)(void); //pour plus tard
    typedef uint (*getterptrUint)(void); //pour plus tard
    typedef bool (*getterptrBool)(void); //pour plus tard
     
     
     
    class DebugMenuEntry
    {
    	//protected :
    public :
     
    		void (*setterFloat)(float);
    		float (*getterFloat)(void);
     
    		void (*setterInt)(int);
    		int (*getterInt)(void);
     
    		void (*setterUint)(uint);
    		uint (*getterUint)(void);
     
    		void (*setterBool)(bool);
    		bool (*getterBool)(void);
     
     
    	public :
     
    		string m_text;
     
    		virtual void Increment() = 0;
    		virtual void Decrement() = 0;
    };
     
     
     
     
    class FloatValue : public DebugMenuEntry
    {
    	float m_Min;
    	float m_Max;
    	float m_Step;
     
    public :
    	FloatValue(string _text, float _step, float _min, float _max, getterptrFloat _getter, setterptrFloat _setter) 
    	{
    		m_Step = _step;
    		m_Min = _min;
    		m_Max = _max;
    		m_text = _text;
     
    		getterFloat = _getter;
    		setterFloat = _setter;
    	}
     
     
    	virtual void Increment()
    	{
    		float currentVal = (*getterFloat)();
    		currentVal += m_Step;
     
    		if(currentVal > m_Max)
    			currentVal = m_Max;
     
    		(*setterFloat)(currentVal);
    	}
     
    	virtual void Decrement()
    	{
    		float currentVal = (*getterFloat)();
    		currentVal -= m_Step;
     
    		if(currentVal < m_Min)
    			currentVal = m_Min;
     
    		(*setterFloat)(currentVal);
    	}
    };
     
     
    class DebugMenuManager
    {
    	//private :
    	public :
    		uint m_uSelectedItem;
    		std::vector< DebugMenuEntry * > m_vEntries;
     
    	DebugMenuManager()	{	}
     
    	void addFloatValue(string _text, float _step, float _min, float _max, getterptrFloat _getter, setterptrFloat _setter)
    	{
    		m_vEntries.push_back( new FloatValue( _text, _step, _min, _max, _getter, _setter) );
    	}
     
     
    	void draw()
    	{
    		//draw content of m_vEntries[i].text + val getter
    	}
     
            void keyboardunct(char key) //to navigate in the menu & change values
           {
             ...
           }
    };
    et dans mon main apres initialisation de mon DebugMenuManager :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    pDebugMenuManager->addFloatValue("ma variable membre float%f", 1, 0, 512, monObjet->getVariableFloat,  monObjet->setVariableFloat);
    Or, à la compilation, sur l'appel à addFloatValue, je suis gratifié du message "un pointeur vers une fonction liée peut uniquement être utilisé pour appeler la fonction". Quelles modifications apporter pour que cela fonctionne ? N'hésitez pas à me demander des explications supplémentaires si quelque chose n'est pas clair. Par avance merci à vous.

  2. #2
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Je serais tenté de dire que ton erreur vient de ça :

    Que j'aurais plutôt remplacé par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    getterFloat = &_getter;
    Mais comme c'est directement sur un pointeur de fonction et non sur la fonction elle-même, je ne suis pas sûr à 100% de ce que j'avance.

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Attention, il y a une différence entre un pointeur sur une fonction libre et un pointeur sur une fonction membre!!! Cela se voit d'ailleurs lors de la déclaration de ce pointeur de fonction car elle prend les formes de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // un pointeur de fonction qui attend une fonction libre
    typedef void (*setterptrFloat)(float);
    // et un pointeur de fonction qui attend un fonction membre d'un objet de type Type
    typedef void (Type::*setterptrFloat)(float);
    Par chance, il n'y a pas qu'une seule différence entre ce qui est fait lors de l'appel d'une fonction membre et ce qui est fait lors de l'appel d'une fonction libre : le compilateur transmet de manière totalement implicite (sans que nous n'ayons rien à faire) un pointeur sur l'objet au départ duquel la fonction membre est appelée (le fameux pointeur this).

    On peut donc utiliser les fonctions bind (boost::bind ou std::bind en C++11) et similaire pour indiquer l'objet qui doit être utilisé pour servir de premier paramètre de la fonction membre ce qui transformerait ton code en quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    addFloatValue("ma variable membre float%f", 1, 0, 512, 
                 std::bind(&DebugMenuManager::getterptrFloat, monObjet), 
                 std::bind(&DebugMenuManager::setterptrFloat, monObjet, std::placeholders::_1));
    (mais j'ai toujours un doute sur la syntaxe exacte... je ne promet donc pas qu'elle le soit ici )

    Ceci dit, je ne crois pas que ce soit ton DebugMenuManager (qui, entre nous a de très bonnes chances d'en faire beaucoup trop au vu de son nom) qui doive recevoir ces fonctions addXXXvalue . Généralement, les termes complexe comme "manager" ou "systeme" méritent amplement d'être "subdivisés" en différentes classes qui pourront prendre une des responsabilités que l'on aurait autrement tendance à donner à notre "manager" ou à notre "system"

    Enfin, tant qu'à utiliser C++ et surtout, tant qu'à utiliser C++11, tu pourrais t'éviter bien des soucis en utilisant std::function et les templates sous ne forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <typename GETRT, //comprend: getter returntype
              typename SETPARAM = GETRT, // comprend setter parameter>
    void addVaue(std::string const & , std::function<GETRT()> const & getter, std::function<void(SETPARAM)> setter){
    /* ... */
    }
    Mais bon, là, j'aborde vraiment des notions particulièrement avancées
    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

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 45
    Points : 25
    Points
    25
    Par défaut
    Salut, et merci pour ta réponse. Il y a des choses que je n'ai pas saisi das ta réponse, lorsque tu transformes mon appel à addFloatValue en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    addFloatValue("ma variable membre float%f", 1, 0, 512, 
                 std::bind(&DebugMenuManager::getterptrFloat, monObjet), 
                 std::bind(&DebugMenuManager::setterptrFloat, monObjet, std::placeholders::_1));
    là dedans, je présume que monObjet doit respectivement être remplacé par monObjet->getMaVariable et par monObjet->setMaVariable. Par contre je ne saisis pas le 1er paramètre, &DebugMenuManager::getterptrFloat, ma classe DebugMenuManager n'a pas de membre getterPtrFloat. En fait, après avoir lu la page de référence http://www.cplusplus.com/reference/functional/bind/ je ne vois pas comment utiliser cette fonction pour mon cas actuel, dans aucun des exemples données on ne cherche à pointer vers une fonction membre d'une instance donnée.

    Par ailleurs, tu as raison sur la subdivisions en classes plus élémentaires plutôt qu'un gros gestionnaire qui en fait trop, mais il s'agit ici d'une toute petite classe, constituée d'un tableau de pointeurs d'accesseurs, et d'une fonction permettant d'afficher la valeur des variables ainsi surveillées, vraiment trois fois rien.

    Pour ce qui est du std::function, je garde ça pour la suite, c'est effectivement très avancé (en tout cas de mon point de vue !), il faut que je me penche là dessus, merci !

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Attends, std::bind() peut vraiment retourner des pointeurs de fonction qui trouvent un paramètre mémorisé à partir de rien?
    Il me semblait que la fonction ne retournait que des foncteurs...

    Surtout que ça exigerait de générer du code dynamiquement à l'exécution...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Réponses: 16
    Dernier message: 26/05/2009, 13h32
  2. Réponses: 8
    Dernier message: 05/07/2007, 13h44
  3. fonction en paramètre d'une fonction ?
    Par tuxout dans le forum Général Python
    Réponses: 1
    Dernier message: 02/06/2007, 15h54
  4. fonction comme paramètre d'une fonction
    Par velociraptor5679 dans le forum C++
    Réponses: 8
    Dernier message: 17/06/2006, 18h19
  5. Réponses: 4
    Dernier message: 01/12/2005, 12h33

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