petit exemple: fabriquer votre propre opérateur ternaire

petit exemple: fabriquer votre propre opérateur ternaire - C++ - Programmation

Marsh Posté le 25-07-2003 à 18:08:55    

/!\ topic sérieux /!\
déconseillé aux débutants. Tout le monde peut lire ce topic et tester le code, mais j'aimerais que l'on reste focalisé sur la technique et pas sur le C++ lui même. Si il y a des points dans le code que vous ne comprenez pas, c'est sans doute une lacune. N'hésitez pas à créer des topics spécifiques (j'aimerais eviter des questions déplacées sur les constructeurs() : truc(chose), les operateur AutreType(), les déclarations imbriquées etc)
 
pour ceux que ça interesse... ce topic à pour but de présenter une technique avancée du C++. Je ne suis pas un véritable expert, donc je peux très bien raconter des bêtises et faire n'importe quoi.
 
Le C++ est langage où l'on manipule les objets par valeur et non par « référence » comme dans des langages comme Java ou Python.
 
Si on analyse l'expression
 
a = b * c
 
cela implique généralement et selon la sémantique habituelle, la création d'un objet temporaire:
 
tmp ( b * c )
a = tmp
 
dans beaucoup d'application ce genre de sémantique ainsi que la création de nombreux objets temporaires ne posent absolument aucun problème: le coup de la création/copie/destruction étant négligeable. Maintenant, vous avez une application où ces opérations ne sont pas du tout négligeables comme dans le cas de calcul scientifique.
 
Le but de ce topic est de montrer une technique permettant de réduire le nombre d'objets temporaires créés. Avant de commencer à vous l'expliquer, je signale qu'il existe une autre technique courremment utilisée qui est basée sur le concept de poignée (handle), c'est à dire que différents objets sont en mesures de partager des membres, et l'intégrité est assurée par un mécanisme de copie sur écriture (copy on write). Pour cela, on utilise souvent des pointeurs intelligents comme les boost::shared_ptr.
 
L'autre technique consiste à jongler sur les mécanismes de surcharge et de résolution de fonction. Je prends ici l'exemple des opérateurs arithmétique + et * mais celà fonctionne avec toutes les fonctions et tous les opérateurs, pour toutes les fonctions n-aires (mais celaest beaucoup plus long)
 
Simplement pour en revenir à l'expression
 
a = (b * c) + d  
 
on va essayer transmettre à a des références aux objets b, c et d et éviter ainsi la création de 2 objets temporaires. Pour réaliser ce mécanisme, on va se servir d'objets porteurs qui vous nous servir à transporter les références jusqu'à a.
cette expression va alors se décomposer
 
a = porteur*(b, c) + d
a = porteur*+(b, c, d)
 
et tou ça n'implique la création d'aucun objet temporaire. a dispose de références à b, c et d et peut librement effectuer les opérations qu'il souhaite et l'affectation.
 
 
bon apres, je sais pas trop expliquer, j'ai essayer de faire un petit exemple, sans doute critiquable. (Notez bien au passage l'implémentation des opérateurs binaires comme fonction externes utilisant les fonctions membres autour de l'affectation, c'est là une tres bonne méthode d'implémentation)
 

Code :
  1. //  source-highlight -v -doc -n -scpp -fhtml operator3.cpp
  2. #include <iostream>
  3. using namespace std;
  4. class Foo
  5. {
  6. public
  7.   struct MultScript;
  8.   struct AddScript;
  9.   struct AddMultScript;
  10.   Foo()
  11.   {
  12.     cout << "Foo()\n";
  13.   }
  14.   Foo(const Foo &other)
  15.   {
  16.     cout << "Foo(Foo)\n";
  17.   }
  18.   ~Foo()
  19.   {
  20.     cout << "~Foo()\n";
  21.   }
  22.   Foo & operator=(const Foo &other)
  23.   {
  24.     cout << "operator=(Foo)\n";
  25.     return *this;
  26.   }
  27.   Foo &operator=(const AddScript &as)
  28.   {
  29.     cout << "operator=(AddScrip)\n";
  30.     return *this;
  31.   }
  32.   Foo &operator=(const MultScript &as)
  33.   {
  34.     cout << "operator=(MultScrip)\n";
  35.     return *this;
  36.   }
  37.   Foo &operator=(const AddMultScript &as)
  38.   {
  39.     cout << "operator=(AddMultScrip)\n";
  40.     return *this;
  41.   }
  42.   Foo &operator+=(const Foo &other)
  43.   {
  44.     cout << "operator+=(Foo)\n";
  45.     return *this;
  46.   }
  47.   Foo &operator*=(const Foo &other)
  48.   {
  49.     cout << "operator*=(Foo)\n";
  50.     return *this;
  51.   }
  52. };
  53. struct Foo::AddScript
  54. {
  55.   AddScript(const Foo &lhs, const Foo &rhs)
  56.     : m_lhs(lhs),
  57.       m_rhs(rhs)
  58.   {}
  59.   operator Foo() const
  60.   {
  61.     cout << "AddScript::Foo()\n";
  62.     Foo tmp(m_lhs);
  63.     tmp+=m_rhs;
  64.     return tmp;
  65.   }
  66.   const Foo &m_lhs;
  67.   const Foo &m_rhs;
  68. };
  69. struct Foo::MultScript
  70. {
  71.   MultScript(const Foo &lhs, const Foo &rhs)
  72.     : m_lhs(lhs),
  73.       m_rhs(rhs)
  74.   {}
  75.   operator Foo() const
  76.   {
  77.     cout << "MultScript::Foo()\n";
  78.     Foo tmp(m_lhs);
  79.     tmp*=m_rhs;
  80.     return tmp;
  81.   }
  82.   const Foo &m_lhs;
  83.   const Foo &m_rhs;
  84. };
  85. struct Foo::AddMultScript
  86. {
  87.   AddMultScript(const Foo &a, const Foo &b, const Foo &c)
  88.     : m_a(a),
  89.       m_b(b),
  90.       m_c(c)
  91.   {}
  92.   operator Foo() const
  93.   {
  94.     cout << "AddMultScript::Foo()\n";
  95.     Foo prod(m_b);
  96.     prod*=m_c;
  97.     Foo sum(m_a);
  98.     sum+=prod;
  99.    
  100.     return sum;
  101.   }
  102.   const Foo &m_a;
  103.   const Foo &m_b;
  104.   const Foo &m_c;
  105. };
  106. Foo::MultScript operator*(const Foo &rhs, const Foo &lhs)
  107. {
  108.   cout << "operator*(Foo, Foo)\n";
  109.   return Foo::MultScript(rhs, lhs);
  110. }
  111. Foo::AddScript operator+(const Foo &rhs, const Foo &lhs)
  112. {
  113.   cout << "operator+(Foo, Foo)\n";
  114.   return Foo::AddScript(rhs, lhs);
  115. }
  116. Foo::AddMultScript operator+(const Foo &a, const Foo::MultScript &ms)
  117. {
  118.   cout << "operator+*(Foo, Foo::MultScrip)\n";
  119.   return Foo::AddMultScript(a, ms.m_lhs, ms.m_rhs);
  120. }
  121. int main()
  122. {
  123.   Foo a, b, c, d;
  124.   cout << "\n\n";
  125.   cout << "a=b+c\n";
  126.   a=b+c;
  127.   cout << '\n';
  128.   cout << "a=c*d\n";
  129.   a=c*d;
  130.   cout << '\n';
  131.   cout << "a=b+c+d\n";
  132.   a=b+c+d;
  133.   cout << '\n';
  134.   cout << "a=b*c*d\n";
  135.   a=b*c*d;
  136.   cout << '\n';
  137.   cout << "a=a+b+c+d\n";
  138.   a=a+b+c+d;
  139.   cout << '\n';
  140.   cout << "a=a*b*c*d\n";
  141.   a=a*b*c*d;
  142.   cout << '\n';
  143.   cout << "a=b+c*d\n";
  144.   a=b+c*d;
  145.   cout << '\n';
  146. }


 
Enjoy  :hello:

Reply

Marsh Posté le 25-07-2003 à 18:08:55   

Reply

Marsh Posté le 25-07-2003 à 18:25:50    

Mouai, concepte intéressant...


---------------
Le Tyran
Reply

Marsh Posté le 25-07-2003 à 20:00:35    

Tres interressant, j'utilise une technique similaire pour générer duc ode utilisant des opérations ternaires en AltiVec à partir de l'écriture a*b+c.  Tres tres bon exposé :D

Reply

Marsh Posté le 25-07-2003 à 20:42:29    

Je flagge...pas le temps de lire de suite et certainement au-dessus de mon niveau, mais j'aime apprendre!:jap:

Reply

Marsh Posté le 25-07-2003 à 20:56:50    

pas facile a comprendre tout ca!
Est ce que tu pourrais expliquer ceci:

Code :
  1. Foo::AddScript operator+(const Foo &rhs, const Foo &lhs)
  2.   {
  3.       cout << "operator+(Foo, Foo)\n";
  4.       return Foo::AddScript(rhs, lhs);//que fait cette ligne exactement?
  5.   }


 
 
La sortie pour ceux qui ne peuvent pas executer :

Foo()
Foo()
Foo()
Foo()
 
 
a=b+c
operator+(Foo, Foo)
operator=(AddScrip)
 
a=c*d
operator*(Foo, Foo)
operator=(MultScrip)
 
a=b+c+d
operator+(Foo, Foo)
AddScript::Foo()
Foo(Foo)
operator+=(Foo)
Foo(Foo)
~Foo()
operator+(Foo, Foo)
operator=(AddScrip)
~Foo()
 
a=b*c*d
operator*(Foo, Foo)
MultScript::Foo()
Foo(Foo)
operator*=(Foo)
Foo(Foo)
~Foo()
operator*(Foo, Foo)
operator=(MultScrip)
~Foo()
 
a=a+b+c+d
operator+(Foo, Foo)
AddScript::Foo()
Foo(Foo)
operator+=(Foo)
Foo(Foo)
~Foo()
operator+(Foo, Foo)
AddScript::Foo()
Foo(Foo)
operator+=(Foo)
Foo(Foo)
~Foo()
operator+(Foo, Foo)
operator=(AddScrip)
~Foo()
~Foo()
 
a=a*b*c*d
operator*(Foo, Foo)
MultScript::Foo()
Foo(Foo)
operator*=(Foo)
Foo(Foo)
~Foo()
operator*(Foo, Foo)
MultScript::Foo()
Foo(Foo)
operator*=(Foo)
Foo(Foo)
~Foo()
operator*(Foo, Foo)
operator=(MultScrip)
~Foo()
~Foo()
 
a=b+c*d
operator*(Foo, Foo)
operator+*(Foo, Foo::MultScrip)
operator=(AddMultScrip)
 
~Foo()
~Foo()
~Foo()
~Foo()
Press any key to continue

Reply

Marsh Posté le 25-07-2003 à 21:06:22    

:heink: j'avais dit pas de question à la con.... je vois pas ce que tu comprends pas: a) il y a pas de constructeur par defaut pour les classes *Script b) on construit l'objet qu'on retourne (normal quoi)
 
 
edit : « Press any key to continue »
ho le windozien


Message édité par Taz le 25-07-2003 à 21:08:51
Reply

Marsh Posté le 25-07-2003 à 21:08:36    

++Taz a écrit :

:heink:
 
 
edit : « Press any key to continue »
ho le windozien  


ben ouais c'est pas sencé appeler Foo::AddScript(rhs, lhs)???
Or on y est dans addscript  :heink:  
 
Mais bon je connais plus le C que le c++
 
 
edit : j'ai deja assez de mal comme ca :o


Message édité par polo021 le 25-07-2003 à 21:09:52
Reply

Marsh Posté le 25-07-2003 à 21:09:41    

polo021 a écrit :


ben ouais c'est pas sencé appeler Foo::AddScript(rhs, lhs)???
Or on y est dans addscript  :heink:  
 
Mais bon je connais plus le C que le c++

:pfff: merci de ta participation, au revoir

Reply

Marsh Posté le 25-07-2003 à 21:10:32    

++Taz a écrit :

:pfff: merci de ta participation, au revoir


 :bounce: explique

Reply

Marsh Posté le 25-07-2003 à 21:12:46    

polo021 a écrit :


 :bounce: explique

:heink: que je sache, en C comme en C++, le prototype d'une fonction, c'est
 
<type de retour> nomDeLaFonction([<argument>])
 
je crois que tu ne sais pas ça. franchement je m'attendais pas à ça comme question, on est vendredi mais quand meme

Reply

Marsh Posté le 25-07-2003 à 21:12:46   

Reply

Marsh Posté le 25-07-2003 à 21:22:58    

disons plutot : a quoi sert ceci alors

Code :
  1. struct Foo::AddScript
  2.   {
  3.       AddScript(const Foo &lhs, const Foo &rhs)
  4.         : m_lhs(lhs),
  5.           m_rhs(rhs)
  6.       {}
  7.    
  8.       operator Foo() const
  9.       {
  10.           cout << "AddScript::Foo()\n";
  11.      
  12.           Foo tmp(m_lhs);
  13.           tmp+=m_rhs;
  14.           return tmp;
  15.       }
  16.    
  17.       const Foo &m_lhs;
  18.       const Foo &m_rhs;
  19.   };

c bien ca que tu appeles quand tu fais Foo::AddScript(rhs, lhs), n'est cce pas

Reply

Marsh Posté le 25-07-2003 à 21:26:56    

deux 2 choses l'une:
- tu n'a pas lu l'explication sur le role des classes Script
- « déconseillé aux débutants », pour moi c'est la première fois que tu vois une classe: on ne peut pas faire plus simple que les classes Script. si tu veux apprendre le C++, regarde les bibliolinks, si tu veux qu'on t'aide à créer ta première classe, on t'aidera, si tu veux un conseille de livre, je te donnerai des références. Mais là je peux rien pour toi. En tout cas pas dans ce topic.


Message édité par Taz le 25-07-2003 à 21:27:34
Reply

Marsh Posté le 25-07-2003 à 21:38:52    

restons en là alors [:spamafote]

Reply

Marsh Posté le 25-07-2003 à 21:42:49    

polo021 a écrit :

restons en là alors [:spamafote]

ben fais un autre topic / envoie moi un PM avec le code de AddScript et que te le commente ligne par ligne

Reply

Marsh Posté le 25-07-2003 à 23:18:17    

interressant je me suis dérouler le bordel dans la tête :D (ça fait mal mais ça passe)
=> technique notée dans un coin :D

Reply

Marsh Posté le 25-07-2003 à 23:34:12    

tiens moi j'ai pas la même trace que polo
 

Foo()
Foo()
Foo()
Foo()
 
 
a=b+c
operator+(Foo, Foo)
operator=(AddScrip)
 
a=c*d
operator*(Foo, Foo)
operator=(MultScrip)
 
a=b+c+d
operator+(Foo, Foo)
AddScript::Foo()
Foo(Foo)
operator+=(Foo)
operator+(Foo, Foo)
operator=(AddScrip)
~Foo()
 
a=b*c*d
operator*(Foo, Foo)
MultScript::Foo()
Foo(Foo)
operator*=(Foo)
operator*(Foo, Foo)
operator=(MultScrip)
~Foo()
 
a=a+b+c+d
operator+(Foo, Foo)
AddScript::Foo()
Foo(Foo)
operator+=(Foo)
operator+(Foo, Foo)
AddScript::Foo()
Foo(Foo)
operator+=(Foo)
operator+(Foo, Foo)
operator=(AddScrip)
~Foo()
~Foo()
 
a=a*b*c*d
operator*(Foo, Foo)
MultScript::Foo()
Foo(Foo)
operator*=(Foo)
operator*(Foo, Foo)
MultScript::Foo()
Foo(Foo)
operator*=(Foo)
operator*(Foo, Foo)
operator=(MultScrip)
~Foo()
~Foo()
 
a=b+c*d
operator*(Foo, Foo)
operator+*(Foo, Foo::MultScrip)
operator=(AddMultScrip)
 
~Foo()
~Foo()
~Foo()
~Foo()


 
polo à des
 
Foo(Foo)
~Foo()  
 
je crée un nouvo topic pour en parler et j'essaye de me renseigner

Reply

Marsh Posté le 26-07-2003 à 10:37:47    

polo021 a écrit :


ben ouais c'est pas sencé appeler Foo::AddScript(rhs, lhs)???
Or on y est dans addscript  :heink:  
 
Mais bon je connais plus le C que le c++
 
 
edit : j'ai deja assez de mal comme ca :o


 
AddScript est une classe : on est dans opérator+, qui appelle le constructeur de la classe.
-> AddScript n'est pas une fonction : achète des lunettes :)

Reply

Marsh Posté le 26-07-2003 à 10:41:54    

leneuf22 a écrit :


 
AddScript est une classe : on est dans opérator+, qui appelle le constructeur de la classe.
-> AddScript n'est pas une fonction : achète des lunettes :)

il a fait un topic exprès
http://forum.hardware.fr/forum2.ph [...] h=&subcat=

Reply

Marsh Posté le 26-07-2003 à 10:45:11    

leneuf22 a écrit :


 
AddScript est une classe : on est dans opérator+, qui appelle le constructeur de la classe.
-> AddScript n'est pas une fonction : achète des lunettes :)

:sol:  
Comprends mieux maintenant [:ddr555]

Reply

Marsh Posté le 26-07-2003 à 21:11:58    

si ce genre de petite mémo plait, j'en referais peut être. Non?

Reply

Marsh Posté le 27-07-2003 à 01:39:05    

Taz a écrit :

si ce genre de petite mémo plait, j'en referais peut être. Non?


 
[:calin]
 
http://membres.lycos.fr/cybear/Forum/topicR.gif
 
 
C'est bieng ce genre de wrappers, mais il faut bien en mesurer la portée.
Par exemple avec ce genre d'opérations:
 

Code :
  1. Foo a,b,c,d,e,r;
  2. r=a+b+c+e;


 
On n'économise qu'un objet temporaire Foo avec le wraper AddScript au lieu de la méthode classique (i.e friend Foo Foo::operator+(const Foo&, const Foo& )).


Message édité par schnapsmann le 27-07-2003 à 01:46:37

---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 27-07-2003 à 01:48:59    

ben c'est déjà pas mal, et puis si tu te réfères au titre du topic, ce n'est pas l'objet du topic. mais je considere que c'est déjà un petit plus non négligeable. pas possible de faire du quaternaire avec que des + avec la meme technique par ce que c'est la meme précédence, c'est donc évalué comme a+b+c+d = ((a+b)+c)+d)


Message édité par Taz le 27-07-2003 à 01:59:55
Reply

Marsh Posté le 27-07-2003 à 01:58:17    

Taz a écrit :

ben c'est déjà pas mal, et puis si tu te réfères au titre du topic, ce n'est pas l'objet du topic. mais je considere que c'est déjà un petit plus non négligeable. et puis la voix est ouverte pour faire un opérateur quaternaire (y a plus qu'a rajouté une classe AddAddscript tres simple et a surchargé + et c'est réglé)


 
Mais oui je n'ai pas prétendu le contraire  [:calin]  
 
Dommage qu'on ne puisse pas bidouiller les précédences et associativités des opérateurs selon leur type (comme en ocaml) ce qui permettrait des optimisations automatiques pour tous les opérateurs n-aires.


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 27-07-2003 à 02:09:55    

j'ai edité, mais je complète: la seule bidouille qu'on peut ajouter permet de réduire la durée de vie des objets temporaires, on peut alors obtenir au lieu de ça  
 

a=a+b+c+d
operator+(Foo, Foo)
Add2Script::Foo()
Foo(Foo)
operator+=(Foo)
operator+(Foo, Foo)
Add2Script::Foo()
Foo(Foo)
operator+=(Foo)
operator+(Foo, Foo)
operator=(Add2Scrip)
~Foo()
~Foo()


 
ceci
 
 

a=a+b+c+d
operator+(Foo, Foo)
operator+(Foo::Add2Script, Foo)
Add2Script::Foo()
Foo(Foo)
operator+=(Foo)
~Foo()
operator+(Foo::Add2Script, Foo)
Add2Script::Foo()
Foo(Foo)
operator+=(Foo)
~Foo()
operator=(Add2Script)

 
 
c'est peut etre pas mal de changer la précédence/priorité, mais je sais pas si c'est vraiment source de confusion à ce moment là... et au niveaux des conversion, y a pas de problème?

Reply

Marsh Posté le 27-07-2003 à 02:10:56    

cela dit ça doit etre difficile de définir une relation pyramidale pour la resolution d'une expression, ça va contre le principe d'évaluation de gauche à droite..., donc je saisis pas trop comment le changement de priorité change quelque chose: tu ne peux pas dire: l'addition de ces 2 types est prioritaire à l'addition de ces 2 types... si? et ça marche comment si ton opérateur n'est pas symétrique? je peux comprendre l'interet mais je suis pas sur que ça soit une bonne chose. et le C++ est ce qu'il est. on surcharge, on ne définit pas, donc ce n'est pas possible de changer la priorité. enfin, là n'est pas la question, on est pas vraiment là pour faire des comparaisons...


Message édité par Taz le 27-07-2003 à 02:26:10
Reply

Marsh Posté le 27-07-2003 à 02:23:02    

Taz a écrit :

cela dit ça doit etre difficile de définir une relation pyramidale pour la resolution d'une expression, ça va contre le principe d'évaluation de gauche à droite..., donc je saisis pas trop comment le changement de priorité change quelque chose: tu ne peux pas dire: l'addition de ces 2 types est prioritaire à l'addition de ces 2 types... si?


 
au temps pour moi, il s'agit plutot de privilégier l'opérateur de plus grande arité sur les autres. C'est faisable avec un parser LALR1.


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 27-07-2003 à 02:27:01    

SchnapsMann a écrit :


 
au temps pour moi, il s'agit plutot de privilégier l'opérateur de plus grande arité sur les autres. C'est faisable avec un parser LALR1.

:heink: en infixé, c'est faisable? tu fais une rapide explication/exemple ? j'ai du mal avec les opérateurs b-aires n>2 en infixé. je réfléchis, et c'est possible qu'en pas infixé il me semble


Message édité par Taz le 27-07-2003 à 02:33:30
Reply

Marsh Posté le 27-07-2003 à 02:56:17    

Taz a écrit :

:heink: en infixé, c'est faisable? tu fais une rapide explication/exemple ? j'ai du mal avec les opérateurs b-aires n>2 en infixé


 
rapide non  :o  
 
Il faut se placer dans le cadre d'un compilo LR1 en fé :o
Ce qui permet de changer les règles de décalage/réduction suivant le type de token en haut de la pile. NB: c'est tjrs de l'infixe mais c'est faisable... c'est justement une limitation des compilos LALR1 qui se contentent de "simples" tables de shift/reduce pour effectuer le parsing.
 
Ensuite l'idée c'est de raffiner la règle de réécriture d'un opérateur pour le type dont tu veux optimiser l'opérateur n-aire, en changeant son associativité à droite (comme pour le '=' classiquement).


Message édité par schnapsmann le 27-07-2003 à 02:58:14

---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 27-07-2003 à 02:59:50    

ok, j'avais po vu ça comme ça

Reply

Marsh Posté le 28-07-2003 à 13:37:26    

Retour au topic.
Taz il me semble que ton exemple ne marche pas si bien que ca ...
 
En effet, les operateurs Foo() appellent une à deux fois le constructeur de Foo ... (pour sum et prod non ?)  
DONC : il a bien construction d'objet temporaire ??
Ou alors les opérateurs de transtypage entre classes ont un comportement spécial qui m'est inconnu ?? (et donc éclaircissement stp)
 
De plus, si on veut ajouter une donnée dans Foo (style un double) il faut modifier lourdement le code :
 

Code :
  1. class Foo {
  2.   public:
  3.   struct AddScript
  4.   {
  5.       AddScript(const Foo & lhs, const Foo & rhs)
  6.   :m_lhs(lhs), m_rhs(rhs) {}
  7.    
  8.       const Foo & m_lhs;
  9.       const Foo & m_rhs;
  10.   };
  11.   struct MultScript
  12.   {
  13.       MultScript(const Foo & lhs, const Foo & rhs)
  14. :m_lhs(lhs), m_rhs(rhs) {}
  15.  
  16.       const Foo & m_lhs;
  17.       const Foo & m_rhs;
  18.   };
  19.   struct AddMultScript
  20.   {
  21.       AddMultScript(const Foo& a, const Foo& b, const Foo& c)
  22. :m_a(a), m_b(b), m_c(c) {}
  23.       const Foo & m_a;
  24.       const Foo & m_b;
  25.       const Foo & m_c;
  26.    };
  27.     Foo(double in):d(in) {
  28. cout << "Foo()\n";
  29.     }
  30.    
  31.     Foo(const Foo & other):d(other.d) {
  32. cout << "Foo(Foo)\n";
  33.     }
  34.    
  35.     ~Foo() {
  36. cout << "~Foo()\n";
  37.     }
  38.     Foo & operator=(const Foo & other) {
  39. cout << "operator=(Foo)\n";
  40. d = other.d;
  41. return *this;
  42.     }
  43.     Foo & operator=(const AddScript & as) {
  44. cout << "operator=(AddScrip)\n";
  45. d = as.m_lhs.d+as.m_rhs.d;
  46. return *this;
  47.     }
  48.     Foo & operator=(const MultScript & as) {
  49. cout << "operator=(MultScrip)\n";
  50. d = as.m_lhs.d*as.m_rhs.d;
  51. return *this;
  52.     }
  53.     Foo & operator=(const AddMultScript & as) {
  54. cout << "operator=(AddMultScrip)\n";
  55. d = as.m_a.d*as.m_b.d+as.m_c.d;
  56. return *this;
  57.     }
  58.     Foo & operator+=(const Foo & other) {
  59. cout << "operator+=(Foo)\n";
  60. d+=other.d;
  61. return *this;
  62.     }   
  63.     Foo & operator*=(const Foo & other) {
  64. cout << "operator*=(Foo)\n";
  65. d*=other.d;
  66. return *this;
  67.     }
  68.     double d;
  69. };
  70. Foo::MultScript operator*(const Foo & rhs, const Foo & lhs)
  71. {
  72.     cout << "operator*(Foo, Foo)\n";
  73.     return Foo::MultScript(rhs, lhs);
  74. }
  75. Foo::AddScript operator+(const Foo & rhs, const Foo & lhs)
  76. {
  77.     cout << "operator+(Foo, Foo)\n";
  78.     return Foo::AddScript(rhs, lhs);
  79. }
  80. Foo::AddMultScript operator+(const Foo & a, const Foo::MultScript & ms)
  81. {
  82.     cout << "operator+*(Foo, Foo::MultScrip)\n";
  83.     return Foo::AddMultScript(a, ms.m_lhs, ms.m_rhs);
  84. }
  85. int main()
  86. {
  87.     Foo a(1), b(2), c(3), d(4);
  88.     cout << "\n\n";
  89.     cout << "a=b+c\n";
  90.     a = b + c;
  91.     cout << "a=" << a.d << endl;
  92.     cout << '\n';
  93.     cout << "a=c*d\n";
  94.     a = c * d;
  95.     cout << '\n';
  96.     cout << "a=b+c*d\n";
  97.     a = b + c * d;
  98.     cout << '\n';
  99. }

 
 
La ca marche, la valeur de d est modifié corretement ET aucun objet temporaire n'est crée. Evidemment, il est nécessaire de surcharger + et * pour qu'ils gérent les cas :
 
Foo + xxScript
xxScript + Foo
xxScript + xxScript
 
Foo * xxScript
xxScript * Foo
xxScript * xxScript
 
Voila ... qu'en penses-tu ??

Reply

Marsh Posté le 28-07-2003 à 13:41:12    

Joel F a écrit :

Retour au topic.
Taz il me semble que ton exemple ne marche pas si bien que ca ...
 
En effet, les operateurs Foo() appellent une à deux fois le constructeur de Foo ... (pour sum et prod non ?)  
DONC : il a bien construction d'objet temporaire ??
Ou alors les opérateurs de transtypage entre classes ont un comportement spécial qui m'est inconnu ?? (et donc éclaircissement stp)
 
 


 
 :jap:  
Sauf optimisation du compilo y a bien ndouble appel du constructeur de recopie.


Message édité par LetoII le 28-07-2003 à 13:41:32

---------------
Le Tyran
Reply

Marsh Posté le 28-07-2003 à 13:49:52    

je vois pas trop de quel cas tu parle? pour a+b, a*b et a*b+c, je ne vois d'objet temporaire?

Reply

Marsh Posté le 28-07-2003 à 13:51:44    

Taz a écrit :

je vois pas trop de quel cas tu parle? pour a+b, a*b et a*b+c, je ne vois d'objet temporaire?


 
C dans les operateurs de transtypage vers foo, même s'ils servent pas pour les calculs, y a un petit pb dedans.


---------------
Le Tyran
Reply

Marsh Posté le 28-07-2003 à 13:55:19    

Moi je ne vois pas de problème. c'est réalisé de manière la plus atomique possible. je vois meme pas la difference avec ton code, si ce n'est qu'il se passe vraiment quelque chose dedans

Reply

Marsh Posté le 28-07-2003 à 14:01:25    

Rien que là, il y a un truc qui me gêne un peu :
 

Code :
  1. struct Foo::AddMultScript
  2. {
  3. AddMultScript(const Foo &a, const Foo &b, const Foo &c)
  4.    : m_a(a),
  5.      m_b(b),
  6.      m_c(c)
  7. {}
  8. operator Foo() const
  9. {
  10.    cout << "AddMultScript::Foo()\n";
  11.    // et de un objet temporaire
  12.    Foo prod(m_b);
  13.    prod*=m_c;
  14.    // et de deux
  15.    Foo sum(m_a);
  16.    sum+=prod; 
  17.      
  18.     return sum;
  19. }
  20. const Foo &m_a;
  21. const Foo &m_b;
  22. const Foo &m_c;
  23. };

 
 
La création des objets temporaires n'apparaît pas dans les logs parce que j'ai l'impression qu'à aucun moment tu ne fais réellement l'opération arithmétique (pas d'appel au transtypage par l'opérateur Foo(), comme disait Leto2).
Ou alors j'ai rien compris, évidemment...

Reply

Marsh Posté le 28-07-2003 à 14:03:25    

Taz a écrit :

Moi je ne vois pas de problème. c'est réalisé de manière la plus atomique possible. je vois meme pas la difference avec ton code, si ce n'est qu'il se passe vraiment quelque chose dedans


 
La différence c qu'il a virré les operateurs de transtypage... J'ai pas regardé en détail mais oui apparement c la même chose que ce que tu as fait  [:ddr555]


Message édité par LetoII le 28-07-2003 à 14:03:46

---------------
Le Tyran
Reply

Marsh Posté le 28-07-2003 à 14:05:55    

umag a écrit :

Rien que là, il y a La création des objets temporaires n'apparaît pas dans les logs parce que j'ai l'impression qu'à aucun moment tu ne fais réellement l'opération arithmétique (pas d'appel au transtypage par l'opérateur Foo(), comme disait Leto2).
Ou alors j'ai rien compris, évidemment...


 
Ben c fait exprès qu'on passe pas par le transtypage, justement pour pas créer d'objet intermédiaire.


---------------
Le Tyran
Reply

Marsh Posté le 28-07-2003 à 14:09:07    

en fait y a besoin des opérateurs de transtypage, à moins fournir des constructeurs, sinon voif F(Foo) ne peut fonctionner avec F(a+b)
 
après ça m'a parru plus élégant et passe partout. c'est vrai que pour a+b+c, on peut encore spécialiser avec une classe Add3Script. mais le pincipal avantage que je vois, c'est qu'avec les opérateurs de conversion, on peut tres bien envisager ce genre de technique avec n'importe quelle classe sans avoir besoin de la modifier.

Reply

Marsh Posté le 28-07-2003 à 14:13:40    

LetoII a écrit :


 
Ben c fait exprès qu'on passe pas par le transtypage, justement pour pas créer d'objet intermédiaire.


 
Ben oui, c'est le principe... ;)
 
Mais il faut quand même faire l'opération quelque part, non ?
 
Donc l'opération, on la fait par exemple là pour le *+ avec un double :

Code :
  1. Foo & operator=(const AddMultScript & as)
  2. {
  3.    cout << "operator=(AddMultScrip)\n";
  4.    d = as.m_a.d*as.m_b.d+as.m_c.d; 
  5.    return *this;
  6. }

 
Et dans ce cas il n'y a effectivement pas d'objet temporaire créé...
Mais il fallait le dire, c'est tout.

Reply

Marsh Posté le 28-07-2003 à 14:14:44    

c'était un peu le but du topic non  :pt1cable:

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed