Partage
  • Partager sur Facebook
  • Partager sur Twitter

Foncteurs C++ , pointeur sur fonction

C++/Qt

    15 août 2018 à 14:19:38

    Bonjour,

    dans le cours de C++ de Mathieu sur les foncteurs, j'aurais besoin d'explicitations sur ce que j'ai mis en gras pour comprendre. Pourriez-vous me donner un exemple de ce qui est en caractère gras ?

    Merci par avance :

    "Ce que l'on aimerait faire, c'est appliquer des changements sur des conteneurs, par exemple prendre un tableau de lettres et toutes les convertir en majuscule. Ou prendre une liste de nombres et ajouter 5 à tous les nombres pairs. Bref, on aimerait appliquer une fonction sur tous les éléments d'un conteneur. Le problème, c'est qu'il faudrait pouvoir passer cette fonction en argument d'une méthode du conteneur. Et cela, on ne sait pas le faire. On ne peut passer que des objets en argument et pas des fonctions.

    Techniquement, ce n'est pas vrai. Il existe des pointeurs sur des fonctions et l'on pourrait utiliser ces pointeurs pour résoudre ce problème. Les foncteurs sont par contre plus simples d'utilisation et offrent plus de possibilités."

    Merci

    -
    Edité par pseudo-simple 16 août 2018 à 7:56:19

    • Partager sur Facebook
    • Partager sur Twitter
      15 août 2018 à 14:47:42

      Pas d'explication, c'est une erreur.

      #include <vector>
      #include <algorithm>
      #include <iostream>
      
      void foo(int i) {
          std::cout << i << std::endl;
      }
       
      int main()
      {
          std::vector<int> v = {3, 4, 2, 8, 15, 267};
          
          std::for_each(std::begin(v), std::end(v), foo);
       
          std::for_each(std::begin(v), std::end(v), [](int i){ std::cout << i << std::endl; });
      }

      On peut passer sans problème une fonction en argument. Ou une lambda. Ou un foncteur. Ou n'importe quoi qui respecte le concept "Callable".

      (On passe notre temps a dire qu'il y a des erreurs dans ce cours. Il faudra bien finir par accepter ca)

      • Partager sur Facebook
      • Partager sur Twitter
        15 août 2018 à 15:38:23

        Salut,

        Combien de fois faudra-t-il te le répéter? oublie ce putain de cours !!!

        Mais donc, pour répondre à ta question, et en gardant bien en tête le fait que tout ce que je pourrai dire ici est devenu obsolète depuis plus de 7 ans:

        Le problème, c'est qu'il faudrait pouvoir passer cette fonction en argument d'une méthode du conteneur. Et cela, on ne sait pas le faire.

        Déjà, c'est complètement faux (du moins tel qu'indiqué et hors de tout contexte),  car il est tout à fait possible de transmettre un pointeur de fonction (libre), et même de transmettre un pointeur de fonction membre (qu'elle soit statique ou non) d'une classe.

        Simplement, c'est plus compliqué, et difficilement adaptable, car la signature des fonctions membres (qu'elles soient statiques ou non) nécessite d'avoir recours à leur nom pleinement qualifié (comprend: au nom de la classe dont elle est issue).  Ainsi, s'il est possible de créer un pointeur de fonction libre sous une forme proche de

        /* soit une fonction ne renvoyant rien et ne prenant aucun 
         * paramètre proche de
         */
        void foo();
        /* on peut créer un pointeur de fonction qui l'utilisera sous
         * la forme de
         */
        typedef void (*CALLBACK) ();
        /* qui sera utilisé sous une forme proche de
        int main(){
            CALLBACK cb= foo;
            cb();
        }

        la même chose avec une fonction membre nécessiterait un code proche de

        /* soit une classe ou une structure */
        struct MaStruct{
            /* exposant une fonction membre statiques ne prenant
             *  pas de paramètres et en renvoyant aucune donnée
             */
            static void foo();
        
        };
        /* on peut créer un pointeur de fonction sous la forme de
         */
        typedef void (* MaStruct::CALLBACK)();
        et l'utiliser sous une forme proche de
        int main(){
            CALLBACK cb = MaStruct::foo;
            cb();
        }

        (par contre, les choses deviennent encore plus compliquée avec les fonctions membres non statiques parce qu'elle prennent un pointeur this comme premier paramètre automatiquement rajouté à la signature de la fonction par le compilateur).

        L'idée est donc de créer ce que l' on peut appeler un "objet fonction" (ou un "foncteur") qui sera -- pour faire simple -- une structure (ou une classe) qui exposera l'opérateur () (car, oui, la paire de  parenthèses correspond à un opérateur, qui prend la forme de générale de TYPE_DE_RETOUR operator () (/* paramètres requis*/); ). Cela pourrait donc prendre une forme proche de

        struct Foncteur{
            void operator() /* const */;
        };

        Et qui nous permettra de profiter du meilleur des deux mondes:

        C'est une structure, et nous pouvons donc l'utiliser comme n'importe quelle strucutre :

        on peut créer une variable dont le type est la structure

        int main(){
            Foncteur fct;
        }

        on peut le transmettre en paramètre à une fonction :

        void foo(Foncteur const & fct);

        On peut même créer des collections de fonceurs:

        int main(){
           std::vector<Foncteur> tab;
        }

        Mais, surtout, à partir du moment où l'on a un objet de type Foncteur, on peut invoquer l'opérateur() sous une forme proche de

        int main(){
            Foncteur fct;
            fct();
        }
        /* et ca fonctionne quand on le recoit comme paramètre */
        void foo(Foncteur const & fct)

        Si le type de retour est un booléen, nous appellerons désignerons de préférence notre structure sous le terme de prédicat, et nous pouvons, bien sur, utiliser le paradigme générique pour déterminer le type des paramètres qui seraient transmis.

        Ainsi, la SL nous offre par exemple le predicat less qui ressemble à quelque chose comme

        template <typename T>
        struct less{
            bool operator()(T const & a, T const & b){
                return a < b;
            }
        };

        (et qui sert -- entre autre -- de type par défaut utilisé pour représenter le comparateur à utiliser dans les classes std::set et std::map, ainsi que dans les différents algorithmes de tri  ;) )

        Maintenant, tout cela a été rendu obsolète en C++11 par l'apparition de std::function qui n'est -- finalement -- rien d'autre qu'une structure générique permettant de créer de foncteurs, avec tout ce que cela implique.

        Ainsi, un code qui aurait pu ressembler à quelque chose comme

        struct Multiplyer{
            int operator(int i, int j) const{
                return i * j;
            }
        };
        struct Additioner{
            int operator(int i, int j) const{
                return i + j;
            }
        }
        template <typename T>
        void callIt(T const & t, int i, int j)){
            std::cout<< t(i, j);
        }
        int main(){
            accIt(Multiplyer(), 3, 5);
            accIt(Additioner(), 3, 5);
        }

        pourra être écrit sous une forme proche de

        int add(int i, int j){
            return i + j;
        }
        int multiply(int i, int j){
            return i * j;
        }
        void doIt(std::function<int (int, int)> const & f, int i, int j){
            std::cout<<f(i,j);
        }
        int main(){
            doIt(add, 3, 5);
            doIt(multiply, 3 5);
            /* voire meme, grâce aux expression lambda) */
            auto a = [](int i, int j){ return i+j;};
            auto b = [](int i, int j){ return i*j;};
            doIt(a, 3, 5);
            doIt(b, 3, 5);
        }

        (et, tu remarqueras que le deuxième code ne nécessite le même nombre de lignes que le premier, malgré le fait qu'il fait deux fois plus de choses ;) )

        -
        Edité par koala01 15 août 2018 à 15:39:13

        • Partager sur Facebook
        • Partager sur Twitter
        Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
          15 août 2018 à 16:09:15

          Merci beaucoup à vous deux. ça m'éclaire

          +1 comme d'habitude et j'ai envoyé un message à OC pour leur dire l'erreur.

          -
          Edité par pseudo-simple 15 août 2018 à 17:33:36

          • Partager sur Facebook
          • Partager sur Twitter
            15 août 2018 à 16:48:15

            YES, man a écrit: > et j'ai envoyé un message à OC pour leur dire l'erreur.

            Sincèrement, tu espères que cela va changer quoi que se soit ?

            • Partager sur Facebook
            • Partager sur Twitter
              15 août 2018 à 16:50:36

              YES, man a écrit:

              j'ai envoyé un message à OC pour leur dire l'erreur.

              (mouahahah)

              koala01 a écrit:

              Simplement, c'est plus compliqué

              Précision : l'approche correcte pour passer une fonction comme argument, c'est de ne pas se casser les pieds et d'utiliser la déduction de types. (En C++ old school, d'utiliser les templates. C'est ce que font les algorithmes standards). Et cela permet d'etre tranquille pour n'importe quel type de callable (fonction, lambda, foncteur, etc).

              #include <iostream>
              
              void foo(auto&& f) {
                  f();
              }
              
              void bar() { std::cout << "bar()" << std::endl; }
              
              int main() {
                  foo(bar);
              }
              

              La syntaxe pour passer une fonction membre est plus complexe... mais en fait, osef. On peut utiliser la meme syntaxe et ajouter une petite lambda et c'est bon.

              #include <iostream>
              
              void foo(auto&& f) {
                  f();
              }
              
              struct A { 
                  void bar() { std::cout << "A::bar()" << std::endl; }
              };
              
              
              int main() {    
                  A a;
                  foo([&a](){ a.bar(); });
              }
              

              Ca serait idiot de s'embeter a ecrire une surcharge de "foo" qui prend une fonction membre, surtout que la syntaxe est un peu moisi :

              #include <iostream>
              
              template<typename T, void(T::*f)()>
              void foo(T& x) {
                  (x.*f)();
              }
              
              struct A { 
                  void bar() { std::cout << "A::bar()" << std::endl; }
              };
              
              int main() {
                  A a;
                  foo<A, &A::bar>(a);
              }
              

              C'est pour cela que je pense que la programmation générique doit être appris assez tot. Ce n'est pas plus compliqué qu'autre chose et ca peut simplifier la vie.

              Et a noter aussi : les foncteurs sont devenus pas mal obsoletes avec les fonctions lambdas.

              -
              Edité par gbdivers 15 août 2018 à 16:52:14

              • Partager sur Facebook
              • Partager sur Twitter
                15 août 2018 à 17:33:19

                Koala01, en relisant ton message, j'ai beaucoup ri avec ton expression "putain de cours". Perso, même si il est imparfait, j'ai un esprit critique qui me permet de sentir les bourdes. La perfection n'existe nulle part.

                De plus, j'ai deux questions :

                1) est-ce que le CALLBACK, c'est un truc  pour les pointeurs sur fonction ?

                2) est-ce que les pointeurs sur fonction, c'est quelque chose du C qui a été repris dans le C++ sans changement ?

                • Partager sur Facebook
                • Partager sur Twitter
                  15 août 2018 à 18:12:51

                  YES, man a écrit:

                  Koala01, en relisant ton message, j'ai beaucoup ri avec ton expression "putain de cours". Perso, même si il est imparfait, j'ai un esprit critique qui me permet de sentir les bourdes. La perfection n'existe nulle part.

                  Je n'ai pas vraiment envie de revenir sur ce débat ...

                  Mais, maintenant que l'on te met de plus en plus "le nez dans la merde" que présente ce cours, as tu déjà essayé de barrer tous les passages concernés par les différents problèmes que l'on t'a signalé?

                  As tu déjà essayé de voir ce qu'il restait de ce "si merveilleux cours" après l'avoir fait?

                  Toi qui te vantes d'avoir un esprit critique, tu devrais peut-être penser à tenter l'expérience et de voir le ratio de ce qui est "à garder" et de ce que l'on t'a déjà dit de jeter.

                  De préférence en gardant à l'esprit que ce que l'on ne t'as pas dit de jeter n'a peut-être simplement pas encore trop attiré notre attention

                  Car je serais ma fois ... curieux de connaitre la réaction que t'inspire ton fameux "esprit critique" face à un tel ratio ;)

                  (je n'ai pas tenté l'expérience, j'ai d'autres choses à foutre, aussi, si tu pouvais nous livrer le ratio en question en même temps que la réflexion que cela t'inspire, ce serait donc vraiment génial :D )

                  Mais, pour répondre à ta question:

                  YES, man a écrit:

                  1) est-ce que le CALLBACK, c'est un truc  pour les pointeurs sur fonction ?

                  2) est-ce que les pointeurs sur fonction, c'est quelque chose du C qui a été repris dans le C++ sans changement ?

                  1 oui,

                  2 oui

                  -
                  Edité par koala01 15 août 2018 à 18:13:52

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                    15 août 2018 à 18:14:02

                    YES, man a écrit:

                    Perso, même si il est imparfait, j'ai un esprit critique qui me permet de sentir les bourdes. La perfection n'existe nulle part.


                    C'est quand même grave de vouloir a tous prix utiliser ce cours et utiliser ton fameux sens critique alors qu'il existe des bons cours.

                    Quand tu suis un cours, tu devrais garder ton esprit critique pour apprendre, au lieu de devoir savoir si le cours est juste ou non... 

                    -
                    Edité par K4kugen 15 août 2018 à 18:14:29

                    • Partager sur Facebook
                    • Partager sur Twitter
                      15 août 2018 à 18:19:18

                      Je ne suis pas du genre à être ingrat : ce cours m'a appris énormément de choses.

                      J'en suis conscient, et il est imparfait. Je suis aussi imparfait, Mathieu aussi. Donc juste un peu de tolérance.

                      @Koala01, merci pour tes deux OUI et OUI

                      pourquoi ce nom de CALLBACK ?

                      En principe, en téléphonie, un callback, c'est un rappel automatique. Pourquoi ce nom ici ? Est-ce vraiment adapté ?

                      Merci

                      -
                      Edité par pseudo-simple 15 août 2018 à 18:27:30

                      • Partager sur Facebook
                      • Partager sur Twitter
                        15 août 2018 à 18:21:00

                        K4kugen a écrit:

                        Quand tu suis un cours, tu devrais garder ton esprit critique pour apprendre, au lieu de devoir savoir si le cours est juste ou non...

                        D'autant plus qu'on ne peut pas être et avoir été...  Quand on apprend, on n'a -- clairement -- pas le recul nécessaire pour savoir si le cours qu'on reçoit est bon ou non.

                        Il faut "avoir été", avoir gagné sa propre expérience pour pouvoir se faire un avis qui ait la moindre valeur!  Ici, la réaction de notre ami s'apparente à celle du teenager gâté qui refuse le conseil de ses parents uniquement parce que c'est, justement, l'avis de ses parents; sans se rendre compte que cet avis a été façonné au gré de leur expérience.

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                          15 août 2018 à 18:25:54

                          Koala01 : je ne dis pas que tu as tort. C'est la nuance. Mais je n'insiste pas dessus.

                          Inutile de repartir sur des dénigrements.

                          Merci aussi par avance si tu peux m'aider pour ma question sur le callback

                          EDIT : Je dois dire aussi que les compléments apportés par les gens du forum m'ont considérablement aidé. Merci à eux tous aussi

                          -
                          Edité par pseudo-simple 15 août 2018 à 18:27:45

                          • Partager sur Facebook
                          • Partager sur Twitter
                            15 août 2018 à 18:36:48

                            Pas la peine d'epiloguer encore une fois sur la question du cours. On previent les gens et ils font ce qu'ils veulent. C'est a eux d'assumer leurs choix. 

                            YES, man a écrit:

                            Je ne suis pas du genre à être ingrat : ce cours m'a appris énormément de choses.

                            J'en suis conscient, et il est imparfait. Je suis aussi imparfait, Mathieu aussi. Donc juste un peu de tolérance.

                            EDIT : les arguments sont un peu idiot. On ne suis pas un cours par gratitude ou par tolérance. 

                            Et surtout, tu insinues qu'on n'est pas respecteux de mathieu en critiquant son cours. Il faut un peu redescendre sur terre. On critique son cours parce qu'il est criticable. Et il le sait très bien.

                            Il faut arrêter de faire le bisounours. Quand on veut apprendre correctement (et certains ici jouent leur avenir professionel), on s'en donne les moyens.

                            -
                            Edité par gbdivers 15 août 2018 à 18:43:25

                            • Partager sur Facebook
                            • Partager sur Twitter
                              15 août 2018 à 18:51:14

                              YES, man a écrit:

                              Koala01 : je ne dis pas que tu as tort. C'est la nuance. Mais je n'insiste pas dessus.

                              Encore heureux que tu ne dises pas que j'ai tort...  Car, loin de le prendre pour moi, je le prendrais pour tous les gens (professionnels ou non) qui on déjà essayé de te faire comprendre quelque chose sur ce forum, qui doivent totaliser près d'un siècle d'expérience à eux tous (si pas plus) et qui ont un avis similaire au mien.

                              YES, man a écrit:

                              Inutile de repartir sur des dénigrements.

                              Tu as sans doute raison, mais voyons un peu le point de vue qui m'incite à perdre mon sang froid et à taper mon poing sur la table (car c'est ce que je fais pour l'instant):

                              Nous t'avons dit et répété sur tous les tons possibles et imaginables ce que nous pensions de ce cours. Et non seulement, nous t'avons donné notre avis sur le sujet, mais nous l'avons justifié de cent manières différentes, y compris en pointant du doigts des passages entiers du cours que l'on décrie.

                              A tel point que je serais très sérieusement curieux de voir ce qu'il resterait de ce cours si nous devions barrer tous les passages qui t'ont personnellement été pointés du doigt comme aberrant, obsolètes ou incorrects.  A mon sens, si on tentait l'expérience, nous ne devrions pas arriver à garder beaucoup plus de... vingt pourcents de ce qui fait le cours actuellement?

                              Et, malgré cela, tu persistes -- sous prétexte d'esprit critique -- à vouloir défendre ce cours bec et ongles;  en dehors de tout sens critique, justement.

                              On dit que même un âne ne bute pas deux fois sur la même pierre.  Mais toi, ce n'est pas deux fois que tu as buté dessus, mais sûrement dix fois, et sans doute même plutôt vingt fois, si pas d'avantage encore !

                              Et tu t'étonnes que l'on perde notre sang froid? Et tu t'étonnes que l'on ait un sourire nerveux ironique lorsque tu viens nous parler de ton "sens critique"?

                              Mais "mon ami", on ne récolte que ce qu'on sème! tu sèmes toi-même depuis près de deux ans (si pas plus) les graines de ta "décribilisation" . Ne t'étonnes pas si tu récolte un manque de crédibilité patent ;)

                              -
                              Edité par koala01 15 août 2018 à 18:53:47

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                15 août 2018 à 19:23:53

                                Bonsoir à tous,

                                si quelqu'un peut m'aider à comprendre cette notion de CALLBACK et son rapport avec sa définition dans la téléphonie, je serai reconnaissant.

                                Merci

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  15 août 2018 à 19:27:09

                                  Aucun rapport avec la telephonie.

                                  -
                                  Edité par gbdivers 15 août 2018 à 19:29:15

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    15 août 2018 à 21:03:58

                                    bonsoir gbdivers,

                                    dans ton code :

                                    #include <iostream>
                                     
                                    void foo(auto&& f) {
                                        f();
                                    }
                                     
                                    struct A {
                                        void bar() { std::cout << "A::bar()" << std::endl; }
                                    };
                                     
                                     
                                    int main() {   
                                        A a;
                                        foo([&a](){ a.bar(); });
                                    }

                                    et plus précisément, pourquoi captures-tu la variable a par adresse ? Est-ce important ici ? Que se passerait-il si tu ne mettais rien ?

                                    Ce serait l'occasion pour moi d'approfondir ce point que m'échappait lorsque j'ai appris les lambdas.

                                    Merci

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      15 août 2018 à 21:09:21

                                      Si "par adresse", tu entends un pointeur, alors regardes bien comment j'appelle la fonction :

                                      a.bar(); 

                                      Donc ce n'est pas un pointeur. C'est une capture par reference. Cf https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture et https://cpp.developpez.com/redaction/data/pages/users/gbdivers/cpp11/#LIV-A 

                                      Et je fais ca simplement pour eviter de copier l'objet.

                                      -
                                      Edité par gbdivers 15 août 2018 à 21:10:36

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        15 août 2018 à 21:55:44

                                        merci

                                        EDIT : j'ai une question sur un pointeur de fonction proposé par Koala01 :

                                        est-ce que la syntaxe proposée

                                        typedef void (* MaStruct::CALLBACK)();

                                        est la syntaxe C++ de

                                        typedef void (* MaStruct::CALLBACK)(void);

                                        en C

                                        ?

                                        Merci par avance car je suis en train d'approfondir plus en profondeur les pointeurs de fonction.

                                        Merci


                                        -
                                        Edité par pseudo-simple 15 août 2018 à 22:04:00

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          15 août 2018 à 23:36:16

                                          Non, parce que cette syntaxe n'existe pas en C ;)

                                          Ce que tu pourrais avoir en C, c'est quelque chose qui serait proche de

                                          typedef void (* CALLBACK) (struct MyStruct *);
                                          struct _mystruct{
                                              CALLBACK drawMe;
                                              CALLBACK update;
                                              /* ... */
                                          };
                                          typedef _myStruct MyStruct;
                                          void draw(MyStruct * ptr);
                                          void update(MyStruct * ptr);
                                          int main(){
                                          
                                          MyStruct * ptr = malloc(sizeof(MyStruct));
                                          if(ptr){
                                              ptr->drawMe = &draw;
                                              ptr->update = &draw;
                                          }
                                          /* ... */
                                          ptr->drawMe(ptr);
                                          ptr->update(ptr);
                                          }

                                          et qui donnerait quelque chose de proche des fonctions membre en C++ ;)

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                            16 août 2018 à 7:52:39

                                            Salut Koala01, avec ton message sur le CALLBACK, ça fait que je suis en train de me documenter sur cette notion de pointeur sur fonction.

                                            Dans un tutoriel, j'arrive sur le sujet de "retourner un pointeur sur fonctions dans une de nos fonctions".

                                            On donne l'exemple de code suivant:

                                            int fonction1(void)
                                            
                                            {
                                            
                                                 return 1;
                                            
                                            }
                                            
                                            
                                            int (* fonction2(void))(void)
                                            
                                            {
                                            
                                                 return fonction1;        /*Ici le retour d'un pointeur sur fonction*/
                                            
                                            }

                                            Ce que j'ai besoin de comprendre, c'est que selon ma compréhension , dans fonction2, quand on écrit "return fonction1", en principe on return un pointeur sur fonction (en fait une copie de quelque chose puisque la retour n'est pas fait par référence, mais par copie).

                                            Alors que le type de retour de fonction2, n'est pas de type pointeur sur fonction, mais de type int.

                                            Donc à priori, ça n'est pas consistant.

                                            Deuxième chose : ce qui métonne, c'est que dans la fonction 2, on ait accès à la variable "fonction 1", dont je ne sais pas si à priori elle peut être considérée comme variable globale. Comment explique-t-on cela ?

                                            Pourriez-vous m'expliquer comment comprendre cela de manière cohérente ?

                                            Merci

                                            -
                                            Edité par pseudo-simple 16 août 2018 à 8:08:03

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              16 août 2018 à 9:17:21

                                              Hello

                                              > Alors que le type de retour de fonction2, n'est pas de type pointeur sur fonction, mais de type int.

                                              Ah? Non. La syntaxe un peu étrange te trompe, mais c'est bien un pointeur de fonction qui est retourne.

                                              > Donc à priori, ça n'est pas consistant.

                                              Donc c'est tout a fait consistant.

                                              > ce qui métonne, c'est que dans la fonction 2, on ait accès à la variable "fonction 1", dont je ne sais pas si à priori elle peut être considérée comme variable globale. Comment explique-t-on cela ? La fonction est fonction1 est déclarée avant que fonction2 ne soit définie. Donc dans le corp de fonction2 le compilateur connais l'existence de fonction1. Ca te permet de l’appeler ou de récupérer son adresse. Exactement comme avec une variable.

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                16 août 2018 à 10:49:44

                                                Merci Elried pour l'info. Ok un peu étonnant

                                                Pour le CALLBACK dont parle Koala01, j'ai poursuivi mon tutoriel dessus. Et si je comprends :

                                                dans les deux morceaux de code :

                                                void foo();
                                                /* on peut créer un pointeur de fonction qui l'utilisera sous
                                                 * la forme de
                                                 */
                                                typedef void (*CALLBACK) ();
                                                /* qui sera utilisé sous une forme proche de
                                                int main(){
                                                    CALLBACK cb= foo;
                                                    cb();
                                                }
                                                
                                                
                                                la même chose avec une fonction membre nécessiterait un code proche de
                                                
                                                	
                                                /* soit une classe ou une structure */
                                                struct MaStruct{
                                                    /* exposant une fonction membre statiques ne prenant
                                                     *  pas de paramètres et en renvoyant aucune donnée
                                                     */
                                                    static void foo();
                                                 
                                                };
                                                /* on peut créer un pointeur de fonction sous la forme de
                                                 */
                                                typedef void (* MaStruct::CALLBACK)();
                                                et l'utiliser sous une forme proche de
                                                int main(){
                                                    CALLBACK cb = MaStruct::foo;
                                                    cb();
                                                }

                                                CALLBACK n'est pas un mot-clé du C++, mais ici Koala01, tu définis toi-même un type que tu appelles CALLBACK et qui est un pointeur sur fonction ne prenant aucun paramètre et ne renvoyant rien non plus. N'hésitez pas à me dire si je fais erreur.

                                                De même dans le deuxième code, il créé le type CALLBACK comme sous-type de la structure mystruct.

                                                -
                                                Edité par pseudo-simple 16 août 2018 à 10:51:13

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  16 août 2018 à 11:02:50

                                                  Plus personne n'utilise ces types.

                                                  std::function FTW

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                                    16 août 2018 à 12:05:02

                                                    (koala01, je crois que tu as fait une tres grosse erreur en parlant des pointeurs de fonction :D Vouloir donner trop d'informations n'est pas pedagogique, ca fait perdre l'attention sur l'essentiel. Et a la fin, il n'aura rien retenu, et surtout pas la bonne syntaxe a utiliser)

                                                    -
                                                    Edité par gbdivers 16 août 2018 à 12:05:24

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      16 août 2018 à 12:06:52

                                                      Koala01, cela m'intéresse et je m'exerce actuellement dessus

                                                      grâce au tutoriel suivant :

                                                      https://openclassrooms.com/fr/courses/1252476-les-pointeurs-sur-fonctions

                                                      , donc tes explications me seront utiles car cela faisait un moment que je projetais de comprendre cette notion.

                                                      C'est en train d'être chose faite.

                                                      Merci

                                                      -
                                                      Edité par pseudo-simple 16 août 2018 à 12:08:41

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        16 août 2018 à 13:03:33

                                                        Parfois on a besoin de manipuler des fonctions comme (comprendre: "via") des variables. En C il y a les pointeurs de fonctions. Dans les langages qui ne permettent pas cela (p.ex. Java), il y a le pattern Commande. En C++, il y a tout ça, et il y a des pointeurs de fonctions membres. La syntaxe du C++ est ce qu'elle est et n'offre pas de moyen syntaxique bas niveau uniforme pour stocker aussi bien des pointeurs de fonctions que des pointeurs de fonction membres.

                                                        On est donc partis sur des types plus complexes pour disposer de cette syntaxe unifiée. Cela a d'abord été boost::function, qui est devenu std::function -- il existe d'autres expérimentations qui n'ont pas été standardisées. Ça, c'est quand on a besoin de stocker et de se souvenir. Quand on a juste besoin de se paramétrer avec une fonction, il y a la syntaxe template qui permet de recevoir ce que l'on peut appeler non officiellement des callables -- i.e. tout ce qui peut s'écrire avec des parenthèses en plus (fonctions, ptr de fonctions, std::function, lambda, foncteurs ou plus précisément des objets fonctions, j'en oublie possiblement).

                                                        -
                                                        Edité par lmghs 16 août 2018 à 13:13:40

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                                          16 août 2018 à 13:32:20

                                                          Merci lmghs,

                                                          J'imagine que Le mot CALLBACK est  une variable choisie par Koala01 , et pas un mot-clé du C/C++ d'après mes recherches

                                                          -
                                                          Edité par pseudo-simple 16 août 2018 à 13:57:02

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            16 août 2018 à 13:45:27

                                                            C'est un typedef dont le nom a été choisi par Koala. Oublie ça pour l'instant.

                                                            -
                                                            Edité par lmghs 16 août 2018 à 13:45:52

                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                                              16 août 2018 à 14:30:57

                                                              Ok, je pense avoir écrit : en gros, le principe de callback, c'est l'idée de passer un morceau de code comme argument à une autre fonction.

                                                              Merci

                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              Foncteurs C++ , pointeur sur fonction

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown