Partage
  • Partager sur Facebook
  • Partager sur Twitter

C++ Scott Meyers, transmission parfaite

C++

    29 octobre 2018 à 12:33:34

    D'autres questions, pour t'aider a repondre a ce problème :

    1. peux tu donner la liste complète de TOUTES les facons d'ecrire un paramètre ?

    (Tu as en donné 2 dans le code précédents : par valeur et par rvalue reference non constante. Quelles sont les autres ? On va se limiter aux syntaxes const et non const, sans utiliser volatile et de classe de la lib standard)

    2. Pour chacune de ces syntaxes, peux tu préciser si on peut appeler cette fonction avec une lvalue, une rvalue ou les 2 ?

    3. Quelles syntaxes choisir, qui permet de ne pas etre ambigue (ie ne pas avoir 2 syntaxes qui acceptent la meme categorie de valeur) ?

    -
    Edité par gbdivers 29 octobre 2018 à 12:34:04

    • Partager sur Facebook
    • Partager sur Twitter
      29 octobre 2018 à 12:37:42

      Salut;

      YES, man a écrit:

      @all et gbdivers : je ne suis pas d'accord avec la position de gbdivers, qui a une position une nouvelle fois erronée sur le perfect forwarding me concernant.

      Je n'ai pas dit que j'allais le comprendre tout de suite. Je sais qu'avant cela, la compréhension des rvalues et lvalues doit être bonne.

      Mais, alors, pourquoi ne te dis tu pas plutôt quelque chose comme "bon,je vais la question "de coté" (prend un gros bloc note pour la noter), on verra plus tard"

      En sachant que, plus tard, ce sera lorsque tu atteindra le point du (bon) cours qui aborde les notions qui te manque.

      Après, il y aura deux solutions :

      • soit, tu sera capable de répondre par toi même à la question
      • soit il y aura encore une "astuce" qui semble t'échaper

      Dans le premier cas, tu as compris, bravo, tu peux envisager d'aller plus loin à ton aise

      Dans le deuxième cas, c'est pas grave : certaines explications ne sont pas toujours aussi claires que ce qu'espérait l'auteur : le forum est là pour toi, et nous t'avons prouvé à de nombreuses reprises que nous sommes en mesure de répondre à la grosse majorité de tes interrogations.

      YES, man a écrit:

      Les aides des autres m'apportent toujours. Donc gbdivers, ne muselle pas les autres, de grâce : ta pédagogie me plaît par petits exercices.

      Gbdivers n'essaye pas de museler les autres, il ne fait qu'émettre un avis sur le forum, ce qui est son droit le plus stricte.

      Le fait est que sa proposition n'est due qu'aux réactions que tu as pu avoir depuis près de deux ans maintenant, et à la frustration que TES réactions ont pu provoquer.

      Si bien que je le dis tout net : je suis bien tenté de me rallier à cette proposition, parce qu'on a tout essayé:

      • la logique,
      • les "calins"
      • la rudesse (qui a valu le passage du modérateur à certains moments)

      Non pas pour jouer au moutons de panurge, comme tu semblerait le croire, ni parce que gbdivers serait notre "gourou", mais parce que les réactions de plus en plus acerbes que tu voit sur le forum à ton égard démontrent clairement un ras le bol général!

      YES, man a écrit:

      @gbdivers : je te répète ce que je t'ai dit : arrête de faire le gourou et chercher à imposer ta vision aux autres. ça ne passera pas avec moi, je te le redis.

      Tu n'as décidément encore rien compris!!!!

      Tu peux t'enfermer dans ton rôle de "défenseur des opprimés" (quoi que matéo n'entre pas vraiment dans cette catégorie) ou dans ton rôle de "pauvre malheureux incompris" si tu le souhaite, il n'empêche que la preuve est devant tes yeux et que tu refuse de la voir:

      Depuis deux ans que tu traines tes basques sur ce forum, tu n'as même pas encore atteint un niveau que l'on pourrait considéré comme "acceptable" de la part d'un débutant, alors que bon nombre de gens qui sont arrivés avec une question concernant le cours de matéo bien après toi, qui ne sont sûrement pas plus intelligents que toi, mais qui sont certainement moins têtu que toi ont atteint ce niveau en trois mois (ou guère plus), et que certains commencent l'ont déjà (largement) dépassé depuis.

      Or, la qualité première d'un bon développeur est de pouvoir se remettre en question!  Tu n'imagines pas le nombre de fois où il m'arrive encore -- malgré mes presque vingt ans de pratique -- de me rendre compte que l'avis de mes interlocuteurs -- et surtout de leurs justifications -- me semble plus cohérent que l'avis que je pouvais avoir.

      Tu n'imagines pas le nombre de fois où n'importe qui décidera -- en son âme et conscience -- qu'un avis divergeant présente des avantages par rapport à son avis personnel, quitte à chercher un compromis permettant de concilier deux avis décidément "trop divergents".

      Cela fait partie de notre vie de "tous les jours" en tant que développeurs!

      Mais toi, après avoir lu deux pages d'un cours, tu as décidé de faire tienne la devise des pays bas : "je maintiendrai" et tu as refusé en bloc toutes les preuves que l'on a pu t'apporter.

      YES, man a écrit:

      ... car si j'avais écouté tes injonctions de stopper le cours de OC, je n'en serais pas là aujourd'hui à avoir autant progressé en C++.

      C'est justement là ta plus grosse erreur: tu crois avoir progressé en C++, alors qu'il n'en est rien!

      Mais, encore une fois, tu n'a pas le recul nécessaire pour t'en rendre compte! Encore une fois, tu es comme ces chevaux de trait qui ont des œillères, et qui ne peuvent donc voir que ce qu'il y a devant eux, sans se douter de tout ce qui peut se trouver sur les cotés.

      Le problème, c'est que ce que te permettent de voir tes oeillères, c'est un ravin remplis rempli de ronces, d'épines et d'obstacles, et qu'elles t'empêchent de voir que, juste à coté, il y a une belle route bien carrossable qui pourrait rendre ton parcours beaucoup plus facile!

      YES, man a écrit:

      Si tu veux pas aider (et je sais que ce n'est pas le cas), alors tu n'aides pas. Et c'est tout. Mais il y a beaucoup de personnes de bonne volonté, qui m'ont considérablement aidé à progresser , et cela continue toujours, donc arrête avec ton diktat de ta pédagogie.

      Oui, mais, au bout d'un moment, la bonne volonté, elle finit par s'effriter...

      YES, man a écrit:

      Je suis en total désaccord avec toi sur plein de points et ça restera ainsi, sois en sûr tant que tu chercheras à t'imposer de la sorte sur le forum de OC. Encore une fois, ton savoir ne te donne aucune prééminence.

      Et tant que tu n'auras pas toi-même compris que, malgré la forme dont gbdivers peut donner à certaines de ses interventions, "ceux qui savent" sont globalement du même avis (pas forcément pour tout, mais pour le principal, à tout le moins), qu'il ne s'agit pas seulement d'une sorte de "duel" entre gbdivers et toi, mais bien d'une "bataille perdue d'avance" entre toi et des moulins ... pardon, et "ceux qui savent", tu ne pourra pas avancer correctement.
      • 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
        29 octobre 2018 à 12:40:47

        @réponse à deedoolith :

        Pour moi, une lvalue, c'est une variable dont on peut prendre l'adresse, qui peut se mettre à gauche d'un égal.

        Pour moi, une rvalue, c'est une entité que l'on met à droite d'un égal, dont on ne peut point nécessairement prendre l'adresse, un objet temporaire aussi

         EDIT :

        @gbdivers :

        toutes les façons d'écrire un paramètres sont d'après mes connaissances actuelles . Si j'en ai omises,  merci de me le dire :

        T n;
        T const n;
        T &n;
        T const& n;
        T &&;
        
        
        Je ne sais pas si il y a :
        
        
        T const &&;
        


        -
        Edité par pseudo-simple 29 octobre 2018 à 12:50:55

        • Partager sur Facebook
        • Partager sur Twitter
          29 octobre 2018 à 12:45:34

          YES, man a écrit:

          @gbdivers : je te répète ce que je t'ai dit : arrête de faire le gourou et chercher à imposer ta vision aux autres. ça ne passera pas avec moi, je te le redis.

          A vrai dire, la seule personne qui essaie d'imposer sa vision dans l'histoire, c'est toi. Si GB est sur le forum depuis des années et file des coups de main à un paquet de gens depuis un bail et que manifestement ça clashe plus que rarement, c'est avant tout parce que son avis est pertinent. Il n'a rien imposé hein, c'est juste que quand un avis est pertinent et bien étayé, ben on l'accepte.

          YES, man a écrit:

          Mais j'insisterai et je continuerai car si j'avais écouté tes injonctions de stopper le cours de OC, je n'en serais pas là aujourd'hui à avoir autant progressé en C++.

          Sur ce point, on est clairement d'accord. Si tu l'avais écouté, tu n'en serais pas là.

          • Partager sur Facebook
          • Partager sur Twitter

          Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

            29 octobre 2018 à 12:57:03

            Ksass`Peuk a écrit:

            Sur ce point, on est clairement d'accord. Si tu l'avais écouté, tu n'en serais pas là.

            Faut il juste préciser que tu serais beaucoup plus loin dans ton apprentissage?

            EDIT d'autant plus que, sans m'avancer énormément (car je peux me tromper), il y a de fortes chances que le premier à t'avoir fait la remarque concernant le cours n'aie pas été GB, mais sans doute Ksass ` Peuk :p

            (et que le deuxième à avoir essayé de te faire comprendre n'ait été personne d'autre que ... moi...)

            -
            Edité par koala01 29 octobre 2018 à 12:59:21

            • 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
              29 octobre 2018 à 13:02:54

              YES, man a écrit:

              toutes les façons d'écrire un paramètres sont d'après mes connaissances actuelles . Si j'en ai omises,  merci de me le dire :

              T n;
              T const n;
              T &n;
              T const& n;
              T &&;
              
              
              Je ne sais pas si il y a :
              
              
              T const &&;

              Postes un nouveau message quand tu réponds. Quand tu edites, il n'y a pas de notification, on ne voit pas forcement ta reponse.

              Il y a aussi les versions avec pointeurs et avec [], mais ca nous interesse pas ici. Et oui, const&& existe et est valide, mais son utilisation est très exceptionnelle.

              Ok, la question 2 maintenant.

              • Partager sur Facebook
              • Partager sur Twitter
                29 octobre 2018 à 17:25:39

                Alors je complète la version avec pointeurs et [] pour faire du travail propre car depuis que j'ai validé le cours de OC, j'ai décidé de travailler uniquement en mode C++ propre :

                T n;
                T const n;
                T &n;
                T const& n;
                T && n;
                T const && n;
                T *n;
                T const *n;
                T n[];

                Est-ce qu'il en manque ?

                -
                Edité par pseudo-simple 29 octobre 2018 à 17:46:26

                • Partager sur Facebook
                • Partager sur Twitter
                  29 octobre 2018 à 17:48:50

                  Pour les pointeurs, oui. Mais c'est pas important dans cet exo.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    29 octobre 2018 à 17:54:06

                    Bah à vrai dire il manque

                    T * const n;
                    T const * const n;


                    Mais on s'en fiche pas mal xD

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Dream on, Dream on, Dream until your dream comes true
                      29 octobre 2018 à 18:00:58

                      Merci romantik et gb, c'est intéressant ant pour moi, car j'y avais pensé. J'ai hésité.

                      Si j'ai envie de faire ça vraiment proprement, il manque aussi la version pointeur intelligent. Existe t-elle ?

                      • Partager sur Facebook
                      • Partager sur Twitter
                        29 octobre 2018 à 18:07:21

                        Les pointeurs intelligents sont des classes, si tu écris ça pour toutes les classes qui existent tu n'es pas rendu

                        donc ... question 2 ?

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Dream on, Dream on, Dream until your dream comes true
                          29 octobre 2018 à 18:35:32

                          (J'ai précisé qu'on mettait de coté les syntaxes qui utilisent les classes de la lib standard)
                          • Partager sur Facebook
                          • Partager sur Twitter
                            29 octobre 2018 à 18:38:47

                            En réfléchissant sur la question 2 , dont je mets la réponse ci-après

                            j'ai une question intermédiaire à vous soumettre :

                            avez-vous un moyen simple pour se rappeler dans quel cas c'est la valeur ou le pointeur (adresse) qui est constant avec les écritures

                            int const *p;
                            int * const p;
                            const int *p;

                            La réponse à la question 2 , avec mes connaissances actuelles :

                            Je ne suis pas sûr :(merci de m'expliquer sur ce point central) :

                            f(T n);   appel avec rvalue et lvalue
                            f(T const n);  appel  lvalue seulement à cause de const
                            (T &n);       appel avec rvalue et lvalue  
                            f(T const& n);  appel  lvalue seulement à cause de const
                            f(T && n);      appel  rvalue seulement à cause de && ?
                            f(T const && n); appel avec rvalue seulement copier une rvalue me semble pas normal
                            f(T *n) ; le pointeur doit probablement pouvoir accueillir une rvalue ou lvalue en raison de sa souplesse
                            f(T const *n);  appel avec une lvalue seulement à cause du const
                            T * const n;   appel avec une lvalue seulement à cause du const
                            T const * const n; appel avec une lvalue seulement à cause du const
                            T n[];    appel avec rvalue et lvalue




                            -
                            Edité par pseudo-simple 29 octobre 2018 à 18:40:41

                            • Partager sur Facebook
                            • Partager sur Twitter
                              29 octobre 2018 à 18:42:27

                              const s'applique a gauche, sauf s'il n'y a rien a gauche.

                              Et il y a des erreurs dans ta liste. Par exemple, la seconde ligne (par valeur constante) accepte les rvalues. Ecris des codes pour tester ce qui est accepté ou non.

                              • Partager sur Facebook
                              • Partager sur Twitter
                                29 octobre 2018 à 18:45:59

                                EDIT :

                                voici ma liste corrigée après réflexion :

                                f(T n);   appel avec rvalue et lvalue
                                f(T const n);  appel  lvalue et rvalue
                                (T &n);       appel avec rvalue et lvalue  
                                f(T const& n);  appel  lvalue et rvalue
                                f(T && n);      appel  rvalue seulement à cause de && ?
                                f(T const && n); appel avec rvalue seulement copier une rvalue me semble pas normal
                                f(T *n) ; le pointeur doit probablement pouvoir accueillir une rvalue ou lvalue en raison de sa souplesse
                                f(T const *n);  appel avec une lvalue et rvalue
                                f(T * const n);   appel avec une lvalueet rvalue
                                f(T const * const n); appel avec une lvalue et rvalue
                                f(T n[]);    appel avec rvalue et lvalue


                                EDIT 2 :

                                maintenant je pense comprendre l'ambiguïté qu'il y a dans :

                                #include <iostream>
                                
                                void f( int n) {
                                
                                        std::cout<<"f a été appelé par une lvalue";
                                
                                 }
                                void f(int&& n) {
                                    
                                        std::cout<<"f a été appelé par une rvalue";
                                   
                                 }
                                
                                
                                int main() {
                                    
                                    int b{1};
                                    f(b);
                                
                                    
                                    f(1);
                                }


                                Reste à trouver un moyen de faire en sorte de résoudre cette ambiguïté. En quelque sorte, il y aurait besoin que la version avec && soit une spécialisation qui soit prise en compte dans le cas très particulier d'une rvalue en argument.

                                EDIT 3 : Bonjour OC :)

                                Voici la résolution de la question 1 initiale (avec utilisation d'une fonction g) avec 1 code qui est maintenant non ambigu (il compile correctement en tout cas, notez que je n'ai pas qu'une fonction f , mais 2 signatures différentes)  :

                                #include <iostream>
                                
                                void f(int &n) {
                                
                                        std::cout<<"f a été appelé par une lvalue";
                                
                                 }
                                
                                
                                void f(int&& n) {
                                
                                        std::cout<<"f a été appelé par une rvalue";
                                   
                                 }
                                
                                int main() {
                                    // appel de f avec une lvalue
                                    int b{1};
                                    f(b);
                                
                                    // appel de f avec une rvalue
                                    f(1);
                                }
                                
                                
                                



                                -
                                Edité par pseudo-simple 30 octobre 2018 à 11:38:04

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  4 novembre 2018 à 23:32:53

                                  Bonsoir OC ;)

                                  Pourriez-vous corriger mes réponses aux deux premières questions :

                                  Voici ma résolution de la question 1 :

                                  #include <iostream>
                                   
                                  void f(int &n) {
                                   
                                          std::cout<<"f a été appelé par une lvalue";
                                   
                                   }
                                   
                                   
                                  void f(int&& n) {
                                   
                                          std::cout<<"f a été appelé par une rvalue";
                                      
                                   }
                                   
                                  int main() {
                                      // appel de f avec une lvalue
                                      int b{1};
                                      f(b);
                                   
                                      // appel de f avec une rvalue
                                      f(1);
                                  }


                                  Pour la question 2 :

                                  f(T n);   appel avec rvalue et lvalue
                                  f(T const n);  appel  lvalue et rvalue
                                  (T &n);       appel avec lvalue uniquement 
                                  f(T const& n);  appel uniquement avec lvalue et rvalue
                                  f(T && n);      appel  rvalue ou lvalue
                                  f(T const && n); appel avec rvalue seulement c
                                  f(T *n) ; appel avec rvalue ou lvalue
                                  f(T const *n);  appel avec  rvalue et lvalue
                                  f(T * const n);   appel avec une lvalue et rvalue
                                  f(T const * const n); appel avec une lvalue et rvalue
                                  f(T n[]);    appel avec rvalue et lvalue



                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    5 novembre 2018 à 9:31:39

                                    1)

                                    Tu n'as rien pour appeler f avec `const int b{1}`
                                    Je pense cependant que tu peux commencer à essayer d'introduire la fonction g appelant f

                                    2)

                                    Tu commets une erreur essentielle, et qui plus est en désaccord avec ton propre code juste au dessus

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Dream on, Dream on, Dream until your dream comes true
                                      5 novembre 2018 à 11:57:00

                                      Salut romantik,

                                      un grand merci pour ton aide :

                                      Pour le 2) Je pense que tu fais allusion à la ligne :

                                      f(T && n);      appel  rvalue ou lvalue

                                      Originellement, j'aurais dit que l'on peut passer uniquement une rvalue à ce genre de chose, mais après avoir lu la page 13 conseil 1, cas 2, du livre de Scott Meyers, j'ai remis en question cette idée puisque dans le cas des références universelles, il peut y avoir une rvalue ou une lvalue.

                                      qui est passé à une fonction dans le cas de :

                                      template <typename T>
                                      void f(T&& param)
                                      f(expr)

                                      Si je fais erreur, peux-tu m'expliquer ?

                                      Merci


                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        5 novembre 2018 à 12:12:40

                                        Il faut etre clair sur la notation, on s'embrouille un peu.

                                        Quand tu écris :

                                        f(T && n);

                                        ou que tu écris :

                                        template<typename T>
                                        f(T && n);

                                        le T represente 2 choses différentes.

                                        Dans le premier cas, j'interprête (et je pense que les autres interprêtent de la meme façon) comme etant une fonction NON template, T est juste un type quelconque non précisé. (En gros, on aurait pu écrire "f(UnTypeQuelconque && n);". Dans ce cas, n est une rvalue reference.

                                        Dans le second cas, c'est une fonction template et T est un paramètre template.

                                        La particularité de la seconde version est que CE N'EST PAS une rvalue reference. Quand tu as "T&&" avec T qui est un paramétre template, alors c'est une "forward reference" (ou "universal reference", mais je crois que la norme a conservé le premier terme).

                                        Donc pour résumé :

                                        f(T && n);

                                        T n'est pas un paramètre template, n est une rvalue reference et donc accept uniquement des rvalues.

                                        template<typename T>
                                        f(T && n);

                                        T est un paramètre template, n est une forward reference, et donc accepte des lvalue et des rvalues.

                                        Attention ! Quand j'écris "accepte des lvalue/rvalue", je parle de que la fonction accepte comme catégorie de valeurs. Dans TOUS LES CAS, n est une lvalue !

                                        -
                                        Edité par gbdivers 5 novembre 2018 à 12:13:21

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          5 novembre 2018 à 14:31:27

                                          Exact, il y a un bel article sur ça

                                          Mais donc ça provient de la déduction de type, tu remarqueras que si tu appelles

                                          template<typename T>
                                          void f(T &&);
                                          
                                          int main(int, char*[])
                                          {
                                            int x{1};
                                            f(x);       // déduction de type => f(int& &&) => f(int&) => ok
                                            f<int>(x);  // spécification de type => f(int &&) => ne compile pas, x n'est pas une rvalue
                                          
                                            return 0;
                                          }



                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Dream on, Dream on, Dream until your dream comes true
                                            5 novembre 2018 à 15:14:07

                                            Merci gbdivers et romantik. Vous avez parfaitement cerné et éclairci mon incompréhension. C'est devenu limpide, surtout avec l'exemple de romantik qui utilise le vocabulaire de déduction de type de template et de spécification de type.

                                            @romantik, j'imagine que dans ton commentaire , tu voulais plutôt dire :

                                            déduction de type => f(int &&) => f(int&) => ok

                                            avec une esperluette en moins à la place de f'(int& &&) ?

                                            Je vais bientôt passer à la suite de l'exercice de gbdivers

                                            -
                                            Edité par pseudo-simple 5 novembre 2018 à 15:30:23

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              5 novembre 2018 à 15:32:11

                                              Non, il s'agit des references collapsing rules, ça sera peut-être plus clair sur ce tableau

                                              Lors de la déduction de type, x est de type `int&`, donc pour la fonction f tu remplaces ton `T` par `int&` ça donne un paramètre de type `int& &&` et donc par collapsing `int&`

                                              C'est plutôt bien expliqué dans l'article

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                              Dream on, Dream on, Dream until your dream comes true
                                                5 novembre 2018 à 15:38:58

                                                Précision, tout cela est dans le livre :

                                                - item 24 pour la différence entre rvalue ref et universal ref

                                                - item 28 pour le reference collapsing

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  5 novembre 2018 à 18:35:05

                                                  romantik a écrit:

                                                  Lors de la déduction de type, x est de type `int&`, donc pour la fonction f tu remplaces ton `T` par `int&` ça donne un paramètre de type `int& &&` et donc par collapsing `int&`

                                                  ----------------

                                                  Je pourrais acquiescer ton raisonnement. Cependant, tu dis que x est de type int&, alors qu'il est de type int tout court.

                                                  En plus, quand on a à affaire  à expr avec une référence, pour déduire le paramType dans un template fonction, on retire la référence d'après le conseil 1 et 2

                                                  C'est le seul point qui m'échappe. POurquoi au début de ton raisonnement dis-tu que x est de type int&, alors qu'il est de type int ?

                                                  Merci

                                                  -
                                                  Edité par pseudo-simple 5 novembre 2018 à 18:35:47

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Anonyme
                                                    5 novembre 2018 à 19:03:52

                                                    C'est parce que x est une lvalue et est donc déduite comme une référence sur lvalue, sooit int&amp;. Dans la fonction, on a donc int&amp; &amp;&amp; donc la colapsing rule dit qu'on finit avec un int&amp;.

                                                    Je te remets ça ici, au cas où tu le lise enfin : https://zestedesavoir.com/tutoriels/474/la-deduction-de-type-en-c/

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      5 novembre 2018 à 19:04:14

                                                      YES, man a écrit:

                                                      C'est le seul point qui m'échappe. POurquoi au début de ton raisonnement dis-tu que x est de type int&, alors qu'il est de type int ?

                                                      C'est définie comme ça dans la norme C++. C'est expliqué dans l'item 1 du livre, dans le 2 cas : "ParamType est une reference universel". Il est ecrit :

                                                      f(x);  // x est une lvalue, donc T est int&

                                                      Ce sont les régles de déduction des templates.

                                                      Comme expliqué dans le livre dans le conseil 1, quand tu as :

                                                      template<typename T>
                                                      void f(T&& param)
                                                      ...
                                                      f(x);

                                                      tu as un type pour x, un type pour T et un type pour param.

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        5 novembre 2018 à 20:26:46

                                                        @gbdivers : merci à toi, tu as mis le doigt sur la subtilité du cas 2. Scott Meyers dit lui-même que c'est un "cas inhabituel ".

                                                        Selon moi, c'est un peu contre-intuitif par rapport aux notations. Quand j'avais lu ce passage du cas 2, je m'étais dit que ce serait bien de l'approfondir.

                                                        Mais si c'est une règle comme elle est rappelée par Scott Meyers "T et paramType sont tout deux déterminées comme des références lvalue" , alors je n'ai rien à dire, à moins qu'il y a une heuristique pour comprendre.

                                                        gbdivers a écrit:

                                                        J'avais compris ta question. Mais la formulation de ta question (et meme apres ton edition) me laisse penser que tu n'as pas compris les categories de valeurs. D'où ma question. Si tu ne sais pas écrire un code qui permet de "voir" la catégorie de valeur, comment peux tu comprendre la transmission et la transmission parfaite.

                                                        On va faire par étape. 

                                                        1. Ecrire un code qui permet de "voir" les categories de valeur

                                                        Complète le code suivant :

                                                        #include <iostream>
                                                        
                                                        // declaration de f
                                                        void f(...) { ... }
                                                        
                                                        int main() {
                                                            // appel de f avec une lvalue
                                                            f(...);
                                                        
                                                            // appel de f avec une rvalue
                                                            f(...);
                                                        }

                                                        Et il faut que ce code affiche :

                                                        f a ete appele avec une lvalue
                                                        f a ete appele avec une rvalue

                                                        2. La transmission

                                                        Modifie le code de facon a ce que f soit appellé via une fonction g (sans modifier le code de f, et en remplaçant uniquement f par g dans main)

                                                        #include <iostream>
                                                        
                                                        // declaration de f
                                                        void f(...) { ... }
                                                        
                                                        // declaration de g
                                                        
                                                        void g(...) { f(...); } 
                                                        
                                                        int main() {
                                                            // appel de g avec une lvalue
                                                            g(...);
                                                        
                                                            // appel de g avec une rvalue
                                                            g(...);
                                                        }

                                                        Quel est le problème dans ce qui est affiché ?

                                                        3. Perfect forwarding

                                                        Corriger le code en utilisant le perfect forwarding de façon a afficher le résultat attendu.

                                                        -
                                                        Edité par gbdivers 27 octobre 2018 à 23:13:59

                                                        VOICI ma réponse à la question 2 de l'exercice de Gbdivers :

                                                        #include <iostream>
                                                        
                                                        void f(int &n) {
                                                        
                                                                std::cout<<"f a été appelé par une lvalue";
                                                        }
                                                        
                                                        void f(int&& n) {
                                                        
                                                                std::cout<<"f a été appelé par une rvalue";
                                                        
                                                         }
                                                        
                                                         // declaration de g
                                                        
                                                         template <typename T>
                                                         void g(T&& n)
                                                         {
                                                             f(n);
                                                         }
                                                        
                                                        
                                                        
                                                        int main() {
                                                            // appel de f avec une lvalue
                                                            int b{1};
                                                            //f(b);
                                                            g(b);
                                                        
                                                            // appel de f avec une rvalue
                                                            //f(1);
                                                            g(1);
                                                        }
                                                        

                                                        J'ai utilisé un template pour g afin d'avoir quelque chose de générique.
                                                        Le problème, c'est que dans les deux cas, c'est la fonction avec lvalue qui est appelée, ce qui est assez bizarre à priori.

                                                        -
                                                        Edité par pseudo-simple 5 novembre 2018 à 22:20:02

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          5 novembre 2018 à 23:27:27

                                                          Comme dit mainte et mainte fois: une variable est une lvalue.

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            5 novembre 2018 à 23:49:18

                                                            Premier point décrivant les lvalues sur cppreference

                                                            the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;

                                                            Je te déconseille de rajouter des templates, tu ajoutes des points sur lesquels tu as des doutes et donc ça peut empêcher ta comprehension, comme le coup des forwarding reference.

                                                            YES, man a écrit:

                                                            Le problème, c'est que dans les deux cas, c'est la fonction avec lvalue qui est appelée, ce qui est assez bizarre à priori.

                                                            C'est le comportement normal, cf l'affirmation ci dessus, et c'est effectivement un problème, c'est là qu'intervient le perfect-forwarding pour le résoudre

                                                            -
                                                            Edité par romantik 5 novembre 2018 à 23:50:59

                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                            Dream on, Dream on, Dream until your dream comes true
                                                              5 novembre 2018 à 23:51:00

                                                              YES, man a écrit:

                                                              Le problème, c'est que dans les deux cas, c'est la fonction avec lvalue qui est appelée, ce qui est assez bizarre à priori.

                                                              C'est exactement la question que j'avais posé :

                                                              gbdivers a écrit:

                                                              Quel est le problème dans ce qui est affiché ?

                                                              Donc tu as la réponse à ma question : cela affiche 2 fois que c'est une lvalue. C'est une transmission de paramètres "normale", comme tu l'as dit dès ton premier message et comme on te le répète depuis le début :

                                                              YES, man a écrit:

                                                              car les paramètres sont des lvalues

                                                              Donc on en arrive a ma 3eme question :

                                                              gbdivers a écrit:

                                                              3. Perfect forwarding

                                                              Corriger le code en utilisant le perfect forwarding de façon a afficher le résultat attendu.

                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              C++ Scott Meyers, transmission parfaite

                                                              × 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