Partage
  • Partager sur Facebook
  • Partager sur Twitter

Mot-cle Friend change un type?

Sujet résolu
    3 mai 2022 à 8:44:43

    Bonjour

    J'ai créé une fonction pour multiplier un vecteur avec un nombre (double):

    friend std::vector<double> operator*(std::vector<double> const &vecteur, double n);

    Elle était dans une classe Fonction et dans une autre méthode de la Fonction  j'ai fait vecteur * -1, vecteur étant un std::vector<double> mais j'ai reçu une erreur a la compilation :

    error: no match for 'operator*' (operand types are 'std::vector<double>' and 'int')
      126 |     return vec_a + (vec_b * -1);
          |                     ~~~~~ ^ ~~
          |                     |       |
          |                     |       int
          |                     std::vector<double>

    Mais en mettant la fonction operator* en dehors de la classe et en retirant friend j'ai plus eu cette erreur. Je sais que friend permet juste a une classe d'accéder aux attributs prives d'une autre.

    Pourquoi dans ma classe le compilateur considérait -1 comme un int mais en dehors il l'accepte comme double s'il vous plait ?
     
     

    • Partager sur Facebook
    • Partager sur Twitter
      3 mai 2022 à 9:27:10

      Tu mélanges probablement des problèmes liés à plusieurs histoires (friend, conversions, etc) et comme tu ne donnes pas le code en entier, on peut rien en dire.

      Pour ce qui est d'avoir une surcharge d'operateur définie pour double et qu'on appelle avec int, le compilateur ne proteste pas.

      Exemple

      #include <iostream>
      
      class Truc {
      };
      
      Truc operator*(const Truc &t, double d)
      {
      	(void) d;   // unused
      	return t;
      }
      
      int main()
      {
      	Truc t;
      	t = t * 2;         // appel avec int
      	t = t * 3.14;      // appel avec double
      }
      
      

      Compilation : no problemo.

      $ g++ -Wall -Wextra    a.cc   -o a
      $


      Conseil: tester les points litigieux

      • un par un
      • dans un programme à part, minimaliste, qui ne fait que ça.
      On peut reprocher à C et C++ leur syntaxe pour le moins cryptique. Elle a quand même un avantage, il ne faut que peu de code pour tester un truc.

      Il me semble probable que tu t'est planté dans les paramètres. Quand operator* (binaire) est défini dans dans une classe, il n'a qu'un paramètre.
      class Truc {
      public:
      	Truc operator*(double d)
        	{
      		(void) d;   // unused
      		return *this;
      	}
      };
      

      -
      Edité par michelbillaud 3 mai 2022 à 9:36:15

      • Partager sur Facebook
      • Partager sur Twitter
        3 mai 2022 à 9:34:03

        Bonjour,

        > Pourquoi dans ma classe le compilateur considérait -1 comme un int mais en dehors il l'accepte comme double s'il vous plait ?

        -1 est un int, dans la classe, en dehors, peu importe où.

        > j'ai reçu une erreur a la compilation

        C'est parce que le compilateur ne trouvait pas la surcharge d'opérateur, normal, elle était dans une classe d'après ce que tu me dis. Quel intérêt d'ailleurs ? puisque l'opération porte sur des types définis par le langage...

        • Partager sur Facebook
        • Partager sur Twitter
          3 mai 2022 à 9:35:26

          merci pour ta reponse. Voici fonction.hpp
          #ifndef FONCTION_HPP
          #define FONCTION_HPP
          
          
          class Fonction
          {
          private:
          
          public:
          
              // friend std::vector<double> operator*(std::vector<double> const &vecteur, double n);
          }; std::vector<double> operator*(std::vector<double> const &vecteur, double n); // Fonction qui etait dans la classe avec "friend" en debut de ligne std::vector<double> operator*(double n, std::vector<double> const &vecteur); #endif
          La fonction operator* :
          std::vector<double> operator*(std::vector<double> const &vecteur, double n)
          {
              std::vector<double> v;
              for (auto elt : vecteur)
                  v.push_back(elt * n);
              return v;
          }
          std::vector<double> operator*(double n, std::vector<double> const &vecteur) { return vecteur * n; }
          La fonction qui a appelé l'operateur en question:
          std::vector<double> operator+(std::vector<double> vec_a, std::vector<double> vec_b)
          {
              std::size_t max_size = __max(vec_a.size(), vec_b.size());
              std::vector<double> result(max_size);
              vec_b.resize(max_size);
              vec_a.resize(max_size);
              for (std::size_t i = 0; i < max_size; i++)
                  result[i] = vec_a[i] + vec_b[i];
          
              return result;
          }
          std::vector<double> operator-(std::vector<double> vec_a, std::vector<double> vec_b)
          {
              return vec_a + (vec_b * -1); // ICI !!... vec_b * -1. -1 etait signalé comme int mais pas double
          }

          Voila donc ces fonctions, j'espere que vous en saurez plus. 

          >Conseil: tester les points litigieux

          • un par un
          • dans un programme à part qui ne fait que ça

          La surcharge de l'operateur fonctionne bien ailleurs(j'ai d'autres classes avec) mais ici en mettant friend j'avais l'erreur avec -1.
           
           

          Umbre37 a écrit:

          Bonjour,

          > Pourquoi dans ma classe le compilateur considérait -1 comme un int mais en dehors il l'accepte comme double s'il vous plait ?

          -1 est un int, dans la classe, en dehors, peu importe où.

          > j'ai reçu une erreur a la compilation

          C'est parce que le compilateur ne trouvait pas la surcharge d'opérateur, normal, elle était dans une classe d'après ce que tu me dis. Quel intérêt d'ailleurs ? puisque l'opération porte sur des types définis par le langage...


          je me suis rendu compte apres que ca n'avait pas sa place comme methode de la classe. 

          Donc le compilateur ne trouvait pas parceque c'etait dans ma classe ? Comment ? Puisque les autres y sont

          -
          Edité par Asmitta 3 mai 2022 à 9:51:25

          • Partager sur Facebook
          • Partager sur Twitter
            3 mai 2022 à 9:45:57

            Ca serait bien si tu allégeais le code que tu présentes en enlevant, sans pitié, tout ce qui ne cause pas le problème que tu décris.

            Ça, et indiquer ensuite, précisément, messages d'erreur complet et numéros de ligne.

            Je dis pas ça pour être embêtant, c'est la démarche normale pour chercher des erreurs, celle que je serai obligé de faire moi-même pour ton code si un coup d'oeil ne suffit pas à repérer une erreur habituelle. Mais là tu nous refile 6 fonctions friend, dans plusieurs dizaines de lignes, alors ça donne pas envie de jouer aux devinettes.

            Le but, c'est quand même qui tu adoptes une méthodologie de travail efficace pour la résolution des problèmes. Pas juste résoudre celui-ci. Parce que des problèmes avec son code, c'est la vie de tous les jours.

            Il n'y a pas de raison de montrer problème avec la surcharge des opérateurs su un exemple plus long que ça

            #include <iostream>
            #include <vector>
            
            std::vector<double> operator+(const std::vector<double> &v,
                                          double d) {
            	std::vector<double> r;
            	for(auto x: v) {
            		r.push_back(x + d);
            	}
            	return r;
            }
            
            int main()
            {
            	std::vector<double> v = { 1, 2.3, 45.56};
            	v = v + 1000;                         // int
            	for (auto x : v) {
            		std::cout << x << std::endl;
            	}
            }
            



            -
            Edité par michelbillaud 3 mai 2022 à 10:10:46

            • Partager sur Facebook
            • Partager sur Twitter
              3 mai 2022 à 9:50:26

              Pour les littéraux :

              "-1" est un int

              "-1." est un double

              "-1.f" est un float

              > Donc le compilateur ne trouvait pas parceque c'etait dans ma classe ? Comment ? Puisque les autres y sont

              Je n'avais pas vu ton code. Je me basais sur ce que tu en disais. Tes surcharges sont bien toutes en dehors de la classes "Fonction", qui n'a d'ailleurs aucun rapport avec le reste, on peut s'en passer ici. En effet, il n'y a aucun rapport entre ça :

              friend Fonction operator*(Fonction const &fonction_a, double n);

              et ça :

              std::vector<double> operator*(std::vector<double> const &vecteur, double n);

              -
              Edité par Umbre37 3 mai 2022 à 9:59:58

              • Partager sur Facebook
              • Partager sur Twitter
                3 mai 2022 à 9:52:59

                Ca serait bien si tu allégeais le code que tu présentes en enlevant tout ce qui ne cause pas le problème que tu décris.

                C'est fait

                • Partager sur Facebook
                • Partager sur Twitter
                  3 mai 2022 à 10:25:16

                  Comme on se sert pas de ta classe Function, elle saute aussi. Finalement il reste, en simplifiant encore (parce qu'on est dans un problème de type, pas de valeur des résultats) :

                  std::vector<double> operator*(std::vector<double> const &vecteur, double n)
                  {
                  	return {};
                  }
                  
                  std::vector<double> operator+(std::vector<double> vec_a, std::vector<double> vec_b)
                  {
                      return {} ;
                  }
                  
                  
                  std::vector<double> operator-(std::vector<double> vec_a, std::vector<double> vec_b)
                  {
                      return vec_a + (vec_b * -1);
                  }
                  


                  qui ne provoque aucune erreur. Mais où est le problème ?

                  PS: passer les vecteurs par référence constante si on ne veut pas modifier leur contenu.

                  PS2: la réponse à la question d'origine, c'est que peut être tout bêtement que le code qui essayait d'utiliser 'operateur n'incluait pas le fichier d'entete qui le déclarait.   Mais bon, obligé de faire des devinettes....

                  -
                  Edité par michelbillaud 3 mai 2022 à 10:48:55

                  • Partager sur Facebook
                  • Partager sur Twitter
                    3 mai 2022 à 10:58:52

                    >Mais où est le problème ?

                    En declarant la fonction operator* dans la classe Fonction le compilateur semblait ne pas la retrouver..

                    Bon tant pis, tout marche maintenant je vais donc ne plus chercher la cause de cette precedente erreur. 🚶🏼‍♂️🚶🏼‍♂️

                    -
                    Edité par Asmitta 3 mai 2022 à 11:02:32

                    • Partager sur Facebook
                    • Partager sur Twitter
                      3 mai 2022 à 11:31:38

                      Salut,

                      Le problème, c'est que le monsieur s'attend à trouver avoir deux élément pour l'opérateur * : un std::vector<double> et un double.

                      Or, quand tu écrit un code proche de  veca + (vecb  * -1), la partie qui est entre parenthèse (c'est celle qui contient ton opérateur * ) est composée d'un std::vector<double> (ca, c'est bon) et d'un int. Et ca, c'est pas bon.

                      Parce que 1, -1 et 0 (ainsi que n'importe quel nombre qui ne soit pas composé du point représentant la virgule) sera toujours considéré "par défaut" comme étant un entier pour le compilateur.

                      Si tu veux que ton compilateur se rende compte que tu as l'intention d'utiliser un entier, il faut le lui dire de manière explicite en ajoutant le . décimal: veca +(vecb * -1.)

                      Parce que le compilateur ne peut faire certaines conversions que dans des situations bien particulières, qui ne sont pas d'application dans celle où tu te trouve pour l'instant ;)

                      • 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
                        3 mai 2022 à 11:39:05

                        friend n'aurait eu d’intérêt que si la classe qui contient la déclaration amie participait aux paramètres.

                        Ce n'est pas le cas. Donc, non seulement on ne profite pas de l'utilisation première de friend vendue aux débutants (accès privilégié à la partie privée), mais en plus on cache la déclaration qui ne peut alors être résolue que si le type cacheur participe aux paramètres, sauf qu'il ne participe pas... C'est un cas bâtard de hidden-friend qui a complètement foiré. Et obligatoirement ça ne peut pas compiler.

                        Une double correction serait que tu :

                        1. définisses ton propre type vecteur (en surcouche au type standard que tu laisserais tranquille) pour lui conférer une sémantique mathématique

                        2. que tu définisses alors les opérateurs d'arité 2 (aka "binaires") comme des amis cachés.

                        Quant à une classe fonction, je ne vois pas ce qu'elle apporte. Ca sent les habitudes Jaba avec l'utilisation de classes en places d'espaces de noms -- espaces de noms non nécessaires ici => définis un type Vector à toi, et laisse le type standard tranquille.

                        -
                        Edité par lmghs 3 mai 2022 à 12:51:08

                        • 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.
                          3 mai 2022 à 12:43:49

                          Asmitta a écrit:

                          >Mais où est le problème ?

                          En declarant la fonction operator* dans la classe Fonction le compilateur semblait ne pas la retrouver..

                          Bon tant pis, tout marche maintenant je vais donc ne plus chercher la cause de cette precedente erreur. 🚶🏼‍♂️🚶🏼‍♂️

                          -
                          Edité par Asmitta il y a environ 1 heure

                          Peut être que tu as oublié l'include.

                          • Tu as mis tes déclarations dans une classe fourre-tout Function
                          • Tu n'utilises pas d'objets Function
                          • Donc tu ne t'est pas senti obligé de l'inclure, et le compilateur ne te dit jamais qu'il ne connaît pas Function.
                          C'est important de voir pourquoi on s'est planté. Ca arrive souvent, et avec quelques scénarios fréquents. Ca aide à dépanner.

                          Mais on ne peut pas être sur de celui là, parce que tu n'as pas presenté un code complet.

                          -
                          Edité par michelbillaud 3 mai 2022 à 12:46:56

                          • Partager sur Facebook
                          • Partager sur Twitter
                            3 mai 2022 à 12:59:09

                            Je vois plein d’hypothèses être émises, mais... je reste persuadé que la réponse tient en trois 3 mots: hidden friend foiré.

                            ECM à l'appui https://gcc.godbolt.org/z/a7Eefbc83

                            -
                            Edité par lmghs 3 mai 2022 à 13:02: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.
                              3 mai 2022 à 17:15:27

                              michelbillaud a écrit:

                              Asmitta a écrit:

                              >Mais où est le problème ?

                              En declarant la fonction operator* dans la classe Fonction le compilateur semblait ne pas la retrouver..

                              Bon tant pis, tout marche maintenant je vais donc ne plus chercher la cause de cette precedente erreur. 🚶🏼‍♂️🚶🏼‍♂️

                              -
                              Edité par Asmitta il y a environ 1 heure

                              Peut être que tu as oublié l'include.

                              • Tu as mis tes déclarations dans une classe fourre-tout Function
                              • Tu n'utilises pas d'objets Function
                              • Donc tu ne t'est pas senti obligé de l'inclure, et le compilateur ne te dit jamais qu'il ne connaît pas Function.
                              C'est important de voir pourquoi on s'est planté. Ca arrive souvent, et avec quelques scénarios fréquents. Ca aide à dépanner.



                              -
                              Edité par michelbillaud il y a environ 4 heures

                              Mon code est toujours pareil. Apres avoir mis la fonction surchargee en dehors de la classe et donc sans Friend, la compilation a reussie, aucune autre modification.

                              >Mais on ne peut pas être sur de celui là, parce que tu n'as pas presenté un code complet.

                              Tu as dit que tu voulais juste la partie concernée.

                              lmghs a écrit:

                              Je vois plein d’hypothèses être émises, mais... je reste persuadé que la réponse tient en trois 3 mots: hidden friend foiré.

                              ECM à l'appui https://gcc.godbolt.org/z/a7Eefbc83

                              -
                              Edité par lmghs il y a environ 4 heures


                              L'exemple du lien correspond bien a mon cas, je comprends mieux merci.

                              Je peux donc retenir que Il n'est pas recommandé d'écrire la déclaration(signature) d'une fonction de surcharge d'operateur(ou autre fonction peut-être) dans une classe si cette classe n'apparait pas dans les paramètres de la fonction. ?



                              -
                              Edité par Asmitta 3 mai 2022 à 17:21:03

                              • Partager sur Facebook
                              • Partager sur Twitter
                                3 mai 2022 à 17:19:34

                                > mon code est toujours pareil

                                Si j'avais gagné un euro chaque fois que j'ai entendu ça, et qu'on a pu constater qu'en fait non...

                                Mais ne spéculons pas : force est de constater que dans ton code, il n'y a aucun #include 

                                -
                                Edité par michelbillaud 4 mai 2022 à 7:54:21

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  3 mai 2022 à 17:23:07

                                  Le "include" n'a rien a voir je penses, vu que déplacer ma fonction a résolu mon probleme. Et j'avais bien mes includes (je les ai retiré dans le code fourni sur ce sujet quand tu voulais "moins" de code)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    3 mai 2022 à 17:42:44

                                    (il n'y a pas besoin d'include, c'est un problème de déclaration qui devient cachée -- mais effectivement le code montré n'est pas un ECM (Exemple Complet et Minimal))

                                    > Je peux donc retenir que Il n'est pas recommandé d'écrire la déclaration(signature) d'une fonction de surcharge d'operateur(ou autre fonction peut-être) dans une classe si cette classe n'apparait pas dans les paramètres de la fonction. ?

                                    Les règles exactes de résolution de nom sont très complexes, et j'avoue ne pas en maitriser tous les détails (surtout quand il y a `frriend` au milieu). Maintenant, cela me parait être un résumé suffisant d'une règle à retenir.

                                    Toutefois, je me demande si on ne peut pas s'en sortir avec une déclaration préalable de friend avant la déclaration d'amitié, si pour X ou Y (mauvaise!) raison il y avait besoin d'accéder aux membres privés de la classe qui contient les amis. D'un coté je me dis que faire le test serait faisable, de l'autre, je ne vois pas un seul scénario valable pour faire un truc pareil => pas besoin de test. (sans parler que j'ai un vague souvenir que cela pars vite en cacahuète dès que la portée s'enrichit...)

                                    • 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.
                                      4 mai 2022 à 8:19:14

                                      Un scénario de ce genre ?

                                      #include <iostream>
                                      
                                      // Thème : Multiplier un Vecteur par un Scalaire retourne un Vecteur
                                      // 1. la multiplication définie en dehors des classes vecteur et scalaire
                                      // => fonction libre
                                      // 2. a besoin de connaître les détails internes => friend des deux.
                                      
                                      class S;             // decl. pour utilisation dans V
                                      
                                      class V
                                      {
                                          friend V operator*(const V & v, const S & s);
                                      
                                      private:
                                          int m_x, m_y;
                                      public:
                                          V(int x, int y) : m_x{x}, m_y{y} {}
                                          void show() const {
                                              std::cout << "(" << m_x << ", " << m_y << ")" << std::endl;
                                          }
                                      };
                                      
                                      class S                   // def.
                                      {
                                          friend V operator*(const V & v, const S & s);
                                      
                                      private:
                                          int m_s;
                                      public:
                                          S(int s) : m_s{s} {}
                                      };
                                      
                                      V operator*(const V & v, const S & s)
                                      {
                                          return {v.m_x * s.m_s, v.m_y * s.m_s};
                                      }
                                      
                                      int main()
                                      {
                                          V v {2, 3};
                                          S s {4};
                                          v.show();
                                          V v2 = v * s;                      
                                          v2.show();
                                      }
                                      


                                      Execution

                                      $ ./prog 
                                      (2, 3)
                                      (8, 12)
                                      



                                      -
                                      Edité par michelbillaud 4 mai 2022 à 8:21:03

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        4 mai 2022 à 13:46:17

                                        Ca, c'est un code qui a du sens. Le code original... Le type qui a des amis n'a rien à voir avec la choucroute. Sauf pour faire des horreurs: https://gcc.godbolt.org/z/o1KPbnaas
                                        • 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.

                                        Mot-cle Friend change un type?

                                        × 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