Partage
  • Partager sur Facebook
  • Partager sur Twitter

implémentation interne de la bibliothèque standard

C++

    15 octobre 2018 à 9:42:37

    Bonjour

    lors de la compilation d'un code C++, j'obtiens une erreur à la compilation.

    En cliquant sur le message renvoyé par le compilateur, j'arrive sur le morceau de code C++ suivant interne au "standard" (ou au compilateur C++, je ne sais pas comment il faut dire ):

    template<bool, bool, typename>
        struct __copy_move
        {
          template<typename _II, typename _OI>
    	static _OI
    	__copy_m(_II __first, _II __last, _OI __result)
    	{
    	  for (; __first != __last; ++__result, (void)++__first)
    	    *__result = *__first;
    	  return __result;
    	}
        };


    Même si je ne suis pas encore arrivé sur les templates sur le cours de Mathieu, j'en ai déjà vu et j'ai quelques rudiments de connaissance.

    Je souhaite comprendre un peu mieux ce code si possible, donc vos explications seraient les bienvenues :

    1) Pourquoi n'y a t-il pas de nom de variables explicites à côté de

    template<bool, bool, typename>

    et où sont utilisées les bool et typename présents dans cette ligne de code ?

    2) comment fonctionne cette boucle :

    for (; __first != __last; ++__result, (void)++__first)
    	    *__result = *__first;

    car je ne suis pas habitué à avoir des "";" sans rien avant ?

    3) D'ailleurs après "result", il y a une "," et je n'ai pas encore vu ce genre de chose tout comme la notation

    (void)++__first

    qui fait à la fois penser à un pointeur de fonction et à un static_cast.

    Merci par avance pour vos explications

    -
    Edité par pseudo-simple 15 octobre 2018 à 11:12:17

    • Partager sur Facebook
    • Partager sur Twitter
      15 octobre 2018 à 10:30:39

      Salut,

      Ton titre n'est vraiment pas explicite, tu connais le forum, tu peux arranger ça s'il te plaît ?

      YES, man a écrit:

      Même si je ne suis pas encore arrivé sur les templates sur le cours de Mathieu, j'en ai déjà vu et j'ai quelques rudiments de connaissance.



      Toujours pareil le cours de Mathieu ... blablabla ... tu connais la musique
      Ce que tu ne sais peut-être pas encore, c'est qu'il y a un joli cours en gestation sur zeste de savoir, et qu'une première version a été publié. Même si le cours est incomplet, il est intéressant, et ce alors qu'il n'est même pas encore question de pointeur qui est une notion à ne pas balancer de suite à un débutant

      YES, man a écrit:

      1) Pourquoi n'y a t-il pas de nom de variables explicites à côté de

      template<bool, bool, typename>

      et où sont utilisées les bool et typename présents dans cette ligne de code ?


      Je ne peux pas en être certain sans le reste du code, mais ça m'a tout l'air d'une spécialisation partielle de template.

      Il faut savoir que la spécialisation partielle ne peut pas être appliquée à une fonction, ce qui expliquerait pourquoi on definit une structure dans laquelle ne se trouve qu'une fonction statique

      Et ces arguments ne sont effectivement utilisés nulle part, tout ce qui nous interesse là c'est que les 2 premiers soient de type booléen pour pouvoir exécuter ce code spécifique

      YES, man a écrit:

      2) comment fonctionne cette boucle :

      for (; __first != __last; ++__result, (void)++__first)
      	    *__result = *__first;

      car je ne suis pas habitué à avoir des "";" sans rien avant ?



      la boucle for est en réalité composée de trois instructions : l'initialisation, le prédicat d'arrêt (ou plutôt de continuation), et l'incrément

      Cette boucle n'a pas besoin d'initialisation donc la première instruction est vide

      YES, man a écrit:

      3) D'ailleurs après "result", il y a une "," et je n'ai pas encore vu ce genre de chose tout comme la notation

      (void)++__first

      qui fait à la fois penser à un pointeur de fonction et à un static_cast.


      Comme dit précédemment, la boucle for exécute 3 instructions, et dans ce cas ci l'instruction d'incrément a été enrichie parce qu'on souhaite réaliser plus de choses

      En fait tu peux vraiment voir ces boucles comme équivalent

      for( init; predicat; increment)
      {
        // ...
      }
      {
        init;
        while(predicat)
        {
          // ...
          increment;
        }
      }

      donc en fait, quoi que tu mettes dans l'instruction d'incrément, c'est exécuté à chaque tour, c'est une instruction comme une autre

      Quant au (void)++__first, c'est effectivement un cast, par contre je sais pas à quoi il sert, peut-être juste à éviter un warning


      • Partager sur Facebook
      • Partager sur Twitter
      Dream on, Dream on, Dream until your dream comes true
        15 octobre 2018 à 10:41:26

        Salut,

        YES, man a écrit:

        Bonjour

        lors de la compilation d'un code C++, j'obtiens une erreur à la compilation.

        En cliquant sur le message renvoyé par le compilateur, j'arrive sur le morceau de code C++ suivant interne au "standard" (ou au compilateur C++, je ne sais pas comment il faut dire ):

        template<bool, bool, typename>
            struct __copy_move
            {
              template<typename _II, typename _OI>
        	static _OI
        	__copy_m(_II __first, _II __last, _OI __result)
        	{
        	  for (; __first != __last; ++__result, (void)++__first)
        	    *__result = *__first;
        	  return __result;
        	}
            };

        On parle d'implémentation interne de la biblitohèque standard...

        Les explications :

        • template <bool, bool, typename> indique au compilateur qu'il y a trois informations connues à la compilation :
          • Deux valeurs booléens et
          • un type dont on "ignore tout pour l'instant" (mais qui sera connu du compilateur)
        • struct __copy_move indique que l'on va créer une structure de donnée, les deux __ au début du noms indique qu'il s'agit d'une structure interne, propre au compilateur, que l'utilisateur (toi!!!) n'a pas besoin de connaitre
        • template<typename _II, typename _OI> indique que ce qui suit va utiliser deux types de données dont on ignore tout : _II (sans doute un InputIterator et un OutputIterator), dont les types (potentiellement différents) sera néanmoins connus du compilateur
        • static _OI indique qu'il s'agit d'une fonction statique qui renvoye une donnée du type qui est connu par le compilateur pour remplacer le type inconnu pour l'instant représenté par _OI (un OutputIterator ?)
        • __copy_m(_II __first, _II __last, _OI __result)représente le prototype de la fonction dont
          • l'utilisateur (toi!!!) doit ignorer jusqu'à l'existence du fait des deux __ au début du nom
          • le premier paramètre (dont tu dois tout ignorer) est de type _II
          • le deuxième paramètre (dont tu doit tout ignorer) est aussi de type __II
          • le dernier paramètre (dont tu doit tout ignorer) est de type _OI
        • for (; __first != __last; ++__result, (void)++__first)est une boucle "for" presque classique, à ceci près qu'il n'est pas nécessaire d'indiquer la valeur de départ (vu qu'elle est égale à __first)
          • La condition de sortie est que __first n'est pas égal à __last
          • L'évolution des données entre chaque exécution se fait sur deux points :
            • li>on incrémente __result
          • on incrémente __first (avec un cast barbare pour éviter que le compilateur ne gueule)
        • *__result = *__first; est une manipulation "classique" de valeurs pointées : on assigne à "ce qui est pointé par __result" la valeur de "ce qui est pointé par __first".

        Bref, il n'y a pas grand chose de difficile là dedans...

        Et comme l'utilisateur (toi, moi, "nous") n'a pas à savoir que la structure (et la fonction statique qu'elle contient), cela n'a de toutes manière aucun intérêt...


        Même si je ne suis pas encore arrivé sur les templates sur le cours de Mathieu, j'en ai déjà vu et j'ai quelques rudiments de connaissance.

        Je n'ai jamais vu un âne plus buté que toi... Et dieu sait que j'en ai croisés, des têtus!!!!

        Je souhaite comprendre un peu mieux ce code si possible, donc vos explications seraient les bienvenues :

        1) Pourquoi n'y a t-il pas de nom de variables explicites à côté de

        template<bool, bool, typename>

        Parce que tu ne dois donner un nom à quelque chose qu'à partir du moment où tu veux y faire référence "ailleurs dans le code".

        Nous ne faisons référence (au niveau de la structure) ni aux deux valeurs booléennes, ni au type template, nous n'avons donc pas besoin de leur donner des noms ;)

        et où sont utilisées les bool et typename présents dans cette ligne de code ?

        Dans le code que tu présente? nulle part...

        Mais tu dois t'attendre à ce qu'il y ait "quelque chose", "quelque part", qui aura besoin d'une classe template fournissant deux booléen et un type "à déterminer".

        car je ne suis pas habitué à avoir des "";" sans rien avant ?

        Dans une boucle for classique, seuls les deux ";" sont obligatoires, pour indiquer clairement où terminent (et donc où commence) les différentes parties de la boucle, à savoir:

        • les valeurs de départ
        • la condition d'entrée dans la boucle
        • l'évolution des données entre deux exécutions

        Il est "relativement peu fréquent" de croiser une boucle for qui décide de ne pas indiquer une ou deux de ces informations, mais il n'y a rien qui nous l'interdise ;)

        Par contre, tu croisera souvent des "boucles infinies" sous la forme de for(;;): pas de valeur de départ, pas de condition pour entrer dans la boucle, pas d'évolution de données entre deux exécutions

        3) D'ailleurs après "result", il y a une "," et je n'ai pas encore vu ce genre de chose tout comme la notation

        on peut fournir plusieurs valeurs de départ, et on peut faire évoluer plusieurs valeurs entre chaque exécutions de la boucle. Il faut bien être en mesure de séparer les différents éléments. L'opérateur ',' est utilisé à ce titre

        (void)++__first

        qui fait à la fois penser à un pointeur de fonction et à un static_cast.

        Non, cela doit juste faire penser à un transtypage "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
          15 octobre 2018 à 10:49:05

          Le (void) fait péter le warning d'unused result car i++ renvoie une valeur, et là il dit, je ne fais rien de la valeur retournée. Pourquoi pas.

          Dans tous les cas, l'erreur est dans ton code. Montre le nous. Et montre nous aussi le message d'erreur.

          • 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.
            15 octobre 2018 à 11:51:35

            YES, man a écrit:

            1) Pourquoi n'y a t-il pas de nom de variables explicites à côté de

            Attention au vocabulaire. Ce ne sont pas des "variables", mais des "paramètres de template".

            Pour l'operateur comma : https://en.cppreference.com/w/cpp/language/operator_other#Built-in_comma_operator 

            koala01 a écrit:

            Je n'ai jamais vu un âne plus buté que toi... Et dieu sait que j'en ai croisés, des têtus!!!!

            Il faut voir le bon côté des choses. On passe notre temps à dire de ne pas suivre ce cours. Au moins, là, on voit les problèmes que cela pose de ne pas suivre ce conseil, et comment les gens galèrent inutilement a persister dans leur erreur.

            -
            Edité par Benzouye 15 octobre 2018 à 13:10:24

            • Partager sur Facebook
            • Partager sur Twitter
              15 octobre 2018 à 12:36:06

              Je vous demande encore une fois, de stopper certaines remarques agressives proches de l'insulte.

              Les jugements de valeur n'ont rien à faire ici. Votre connaissance du C++ ne vous autorise pas de faire ce genre de bizutage.

              -
              Edité par pseudo-simple 15 octobre 2018 à 12:46:22

              • Partager sur Facebook
              • Partager sur Twitter
                15 octobre 2018 à 12:53:18

                Tu marques un point.

                Mais depuis le temps que l'on te prouve par A + B que le cours de Mathieu Nebra est obsolête et mauvais, tu refuses de te remettre en question.
                A force de persister à foncer dans le mur, on fini par se le prendre en pleine face.

                • Partager sur Facebook
                • Partager sur Twitter
                  15 octobre 2018 à 13:18:38

                  Le problème est qu'il ne s'agit pas d'une jugement de valeur (ie un point de vue subjectif), mais bien une critique objective. 

                  Le C++ "moderne" est une démarche pour comprendre d'où viennent les erreurs et comment les éviter au maximum. Il y a bien sûr des problèmes dans les syntaxes du C++ (et c'est le boulot du comité C++ de corriger cela), mais également dans l'apprentissage du C++ (et c'est normalement le boulot des auteurs de corriger cela... mais on a un gros problème en France sur ce point) et dans les pratiques (et c'est le boulot de tous les devs C++ de corriger cela).

                  Dans ces problèmes liés a l'apprentissage et aux pratiques, il y a un facteur humain a prendre en compte. Ce sont des choses bien connues et pas spécifiques au C++ : résistance au changement, paresse intellectuelle, etc.

                  - Considérer que le premier tuto qu'on trouve est forcément LE bon est un gros problème, c'est pour cela qu'on essaie de "corriger" la trop grande visibilité des mauvais tutos et livres.

                  - Rester sur ce premier tuto, même s'il est mauvais, est un autre problème qu'on voit régulièrement. Les gens préfèrent persister plutôt que de reconnaître qu'ils ont fait une erreur. (C'est dur d'accepter d'avoir fait une erreur. Mais c'est comme cela qu'on apprend).

                  La conséquence, qu'on voit très bien avec toi (avec toutes les questions que tu poses sur le forum), c'est des difficultés de compréhension et un apprentissage lent. C'est une perte de temps et d'énergie pour celui qui apprend. (En plus de lui donner l'impression que le C++ est un langage inutilement compliqué).

                  Ne t'attends pas à ce qu'on arrête de critiquer ta façon d'apprendre. Parce qu'on ne veut pas que d'autres suivent ton exemple.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    15 octobre 2018 à 13:19:32

                    Bonjour,

                    YES, man a écrit:

                    Votre connaissance du C++ ne vous autorise pas de faire ce genre de bizutage

                    Je suis tout à fait d'accord avec cette assertion, sauf qu'il ne s'agit pas là de bizutage, mais de conseils ... même si dans la forme ils sont un poil sarcastiques ...

                    @YESman, merci de ne pas signaler tous les messages qui blessent votre amour propre, car en étant débutant vous allez être obligé de signaler toutes les réponses, notamment lorsque vous vous entêtez à ne pas écouter et suivre les conseils qui vous sont donnés ...

                    Je vous conseille de ravaler un tant soit peu votre fierté (oui je sais que cela est douloureux) et de bien relire les participations des autres membres avant de vous braquer. Essayez de comprendre qu'il n'y a rien de plus pénible que de voir vos réponses ignorées par un débutant, et que cela peut générer aussi de l'exaspération, donc du sarcasme ...

                    @tous, merci de reprendre la discussion plus sobrement, ou, au pire, de ne plus répondre du tout si votre seuil de tolérance est atteint ... ce que je n'espère pas ;)

                    -
                    Edité par Benzouye 15 octobre 2018 à 13:20:13

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                    Anonyme
                      15 octobre 2018 à 13:40:51

                      Je pense, au style de code, que tu utilise MSVC avec Visual Studio. Ça reste un exercice amusant de lire (une partie de) leur implémentation, mais ça demande quelques notions, même si c'est rien de sorcier. :)

                      Si tu veux, je vais être beaucoup moins agressif : « Très cher, il me semblerait, àmon humble opinion, que ce support d'apprentissage ne soit quelque peu passé. Je voudrais, en toute amitié, vous offrir le conseil de chercher d'autres sources de savoir, pour ne point vous voir prendre un chemin qui ne saura que vous voler votre temps tout en vous offrant de bien méchantes habitudes. Très amicalement vôtre,

                      Une créatrice d'instruction pour machine de Turing portant des équipements de protection des mains à base de caoutchouc. »

                      • Partager sur Facebook
                      • Partager sur Twitter
                        15 octobre 2018 à 18:55:39

                        Maintenant que les autres participants habituels du forum m'ont piqué mes coups de gueule, je vais prendre le rôle de "good cop", pour changer.

                        Il n'est pas rare, quand on utilise de travers des fonctionnalités de la STL, que le compilateur indique du code dans le source de celle-ci, car, comme elle a été bien faites (elle, pas comme cette coch..., oups "good cop" j'ai dit), la détection de ce mauvais usage se fait à la compilation, donc dans le code qui l'a "détecté".

                        Après, le code de la STL, c'est assez spécial et le décryptage des erreurs tout un art.

                        Donc, généralement, il est plus efficace de regarder un peu plus attentivement le code qu'on a écrit que de décrypter le message d'erreur.

                        Mais, s'il te prend de faire le Saint-Thomas, il faut commencer par bien lire correctement TOUT le message d'erreur qu'il t'indique, plus ou moins directement, que t'as fait nimportnawak et que tu devrais lire plus attentivement la documentation.

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                          15 octobre 2018 à 19:00:58

                          Merci bacelar , j'ai aussi constaté que ton conseil m'a aidé à plusieurs reprises , auparavant, lorsque le compilateur m'a renvoyé vers du code de la librairie standard.
                          • Partager sur Facebook
                          • Partager sur Twitter
                            15 octobre 2018 à 23:31:25

                            Je ne pense pas que l'étude du code de la SL soit utile avant d'avoir atteint un certain niveau (disons très élevé...), je dirais que c'est comme le code source de boost mais en pire... Quelques notions de template, c'est clairement insuffisant. Ce qui peut en revanche être intéressant, mais pas du tout simple, c'est refaire en exercice certaines parties la bibliothèque standard en partant soit de la doc (plus simple) soit de la norme (beaucoup plus hard, ne serait ce que parce que la norme est beaucoup plus difficile à lire et à comprendre que la doc). Le plus important, c'est quand même de bien l'utiliser et pour cela, tu n'as pas vraiment besoin d'aller te plonger dans les arcanes de la SL, d'autant que si tu descends assez bas, tu vas fatalement finir par tomber sur des appels systèmes totalement opaques qui sont ceux qui font vraiment le boulot et là, il faudra jouer du debugger en mode hardcore (c'est à dire, en ring 0, en disassemble sans les sources, sans les symboles, et là c'est vraiment très chaud, tu vas y passer un temps fou et tu ne vas pas apprendre grand chose...). Comme l'ont dit mes VDD, quand tu as une erreur qui te renvoie sur le code de la SL, tu as meilleur compte d'analyser le message d'erreur pour retrouver la partie fautive de ton code qui l'a provoqué que d'essayer de te pencher sur le code de la SL. C'est d'autant plus vrai, que les implémentations de la SL sont blindées de macros dont le développement à la compilation va potentiellement changer radicalement en fonction de la plateforme, du niveau de support de la norme et des options de compilation, sans parler des bricoles qui sont spécifiques à l'implémentation du compilateur lui même, voir du debugger. Je ne sais pas si c'est toujours le cas, mais la SL de MSVC contenait tout un tas de macros, pour produire des informations supplémentaires que le debugger récupérait pour permettre un debug plus facile, le tas par exemple contenait plus d'informations en debug qu'en release, la pile également, ce qui permettait au debugger de détecter un double delete ou un écrasement de la pile, les itérateurs en debug étaient aussi "enrichis" pour aider à détecter les débordements et les utilisations d'un itérateur invalidé. Si ça se trouve, le code que tu cherches à comprendre, est planté là par une macro de debug...
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                              18 octobre 2018 à 21:20:36

                              lmghs a écrit:

                              Le (void) fait péter le warning d'unused result car i++ renvoie une valeur, et là il dit, je ne fais rien de la valeur retournée. Pourquoi pas.

                              Il ne devrait pas y avoir de warning. Normalement, le cast est là pour éviter une éventuelle surcharge de l'opérateur virgule d'être appelée.

                              -
                              Edité par Tealc13 18 octobre 2018 à 21:21:00

                              • Partager sur Facebook
                              • Partager sur Twitter
                                19 octobre 2018 à 9:23:00

                                hum... bien vu.
                                • 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.

                                implémentation interne de la bibliothèque standard

                                × 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