OVH Cloud OVH Cloud

Operateur + et conversion...

7 réponses
Avatar
Marc Boyer
Je suis en train de surcharger + pour un type entier. Soit
Entier le dit type. Il existe une conversion
implicite de Entier vers int (operator int()) et Entier
possede un constructeur avec un int comme paramêtre.

J'ecris donc ma fonction membre +=, et je fais ma fonction
Entier operator+(const Entier a,const Entier b){
Entier tmp(a);
return tem+=b;
}

Mon problème, c'est que quand j'écris
int i=1;
Entier e = 0;
cout<<e+1;
Il effectue
cout<<int(e)+1;
et pas (comme j'aimerais)
cout<<operator+(e, Entier(1) );

Je peux le "forcer" en déclarant
Entier operator+(const Entier, const int);
Entier operator+(const int, const Entier;
mais ça me fatigue d'avance de devoir écrire à chaque fois 3 operateurs...

Il y a une issue ou c'est comme ça point barre.

Marc Boyer
--
Lying for having sex or lying for making war? Trust US presidents :-(

7 réponses

Avatar
kanze
Marc Boyer wrote in message
news:<bglnvr$noc$...

Je suis en train de surcharger + pour un type entier. Soit Entier le
dit type. Il existe une conversion implicite de Entier vers int
(operator int()) et Entier possede un constructeur avec un int comme
paramêtre.


C'est un moyen exceptionnellement efficace à obtenir des ambiguïtés de
surcharge.

J'ecris donc ma fonction membre +=, et je fais ma fonction
Entier operator+(const Entier a,const Entier b){
Entier tmp(a);
return tem+=b;
}

Mon problème, c'est que quand j'écris
int i=1;
Entier e = 0;
cout<<e+1;
Il effectue
cout<<int(e)+1;
et pas (comme j'aimerais)
cout<<operator+(e, Entier(1) );


Hmmm. J'aurais cru plutôt une ambiguïté. Mais les règles ont changées
souvent, et je ne suis peut-être pas tout à fait à jour. Il y a
peut-être une histoire de const qui lui fait préférer la version
uniquement int.

Mais je ne crois pas. Dans un cas, tu as une conversion utilisateur sur
le premier paramètre. Dans l'autre, sur le deuxième. Et je suis prèsque
certain qu'on n'a pas supprimé la règle que la fonction qui convient la
plus ne peut pas convenir moins à aucun paramètres -- elle doit convenir
plus pour au moins un paramètre, et autant, plus ou moins, pour tous les
autres.

Un essai rapide chez moi montre que Sun CC préfère l'opérateur avec les
Entier, et g++ le considère ambigu. En ajoutant ton compilateur, ça fait
trois compilateurs avec trois résultats différents:-). Je crois que
c'est g++ qui a raison.

Je peux le "forcer" en déclarant
Entier operator+(const Entier, const int);
Entier operator+(const int, const Entier;
mais ça me fatigue d'avance de devoir écrire à chaque fois 3
operateurs...

Il y a une issue ou c'est comme ça point barre.


Si tu as les deux conversions, c'est certain que l'opérateur *peu*
s'effectuer de deux façons. D'après mes expériences, c'est une recette
pour beaucoup d'ambiguïtés. Non seulement pour le compilateur (qui
arrive parfois à trouver des règles qui lui conviennent), mais aussi
pour l'utilisateur (qui ne sait jamais quel opérateur va être appelé).
Dans de tels cas, je conseille fort à établir un hièrarchie dans les
types, et à ne permettre des conversions implicites que dans une
direction dans l'hièrarchie -- si Entier peut se construire d'un int,
alors, pas de conversion implicite vers int.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
Marc Boyer
wrote:
Marc Boyer wrote in message
news:<bglnvr$noc$...

Je suis en train de surcharger + pour un type entier. Soit Entier le
dit type. Il existe une conversion implicite de Entier vers int
(operator int()) et Entier possede un constructeur avec un int comme
paramêtre.


C'est un moyen exceptionnellement efficace à obtenir des ambiguïtés de
surcharge.


Mais ça permet d'initialiser des Entiers à partir d'int,
et de passer des Entiers en paramêtre quand un int est attendu...
Je tente en fait d'écrire la classe "Entiers avec tests de debordement"
dont j'ai besoin et que je n'ai pas trouvée.

Est-ce que je résoudrais le problème en mettant le constructeur
comme "explict" et en proposant un operateur d'affectation
explicit Entier(int)
Entier(Entier)
Entier operator=(int)
Entier operator=(Entier)
operator int()
ou est-ce que ça apportera d'autres problèmes que je n'anticipe
pas pour le moment ?

Un essai rapide chez moi montre que Sun CC préfère l'opérateur avec les
Entier, et g++ le considère ambigu. En ajoutant ton compilateur, ça fait
trois compilateurs avec trois résultats différents:-). Je crois que
c'est g++ qui a raison.


En fait, j'utilise gcc 3.2.2, mais j'ai pas posté exactement
le code qui me posait problème (qui est un template).

Marc Boyer
--
Lying for having sex or lying for making war? Trust US presidents :-(


Avatar
kanze
Marc Boyer wrote in message
news:<bgofqv$9q8$...
wrote:
Marc Boyer wrote in message
news:<bglnvr$noc$...

Je suis en train de surcharger + pour un type entier. Soit Entier
le dit type. Il existe une conversion implicite de Entier vers int
(operator int()) et Entier possede un constructeur avec un int
comme paramêtre.


C'est un moyen exceptionnellement efficace à obtenir des ambiguïtés
de surcharge.


Mais ça permet d'initialiser des Entiers à partir d'int, et de
passer des Entiers en paramêtre quand un int est attendu...


Certes. Mais ça fait aussi que dès qu'une expression est mélangée, avec
les deux types, il est ambigu lequel des deux doit servir.

Je tente en fait d'écrire la classe "Entiers avec tests de
debordement" dont j'ai besoin et que je n'ai pas trouvée.

Est-ce que je résoudrais le problème en mettant le constructeur
comme "explict" et en proposant un operateur d'affectation
explicit Entier(int)
Entier(Entier)
Entier operator=(int)
Entier operator=(Entier)
operator int()
ou est-ce que ça apportera d'autres problèmes que je n'anticipe pas
pour le moment ?


Ça voudrait dire que toutes les opérations mixes se font avec des int,
et non des Entier. Tu pourrais, évidemment, fournir tous les opérateurs
mixes ; ce n'est pas si difficile que ça, à l'aide des macros.

J'aurais une tendance à faire l'inverse : à remplacer l'opérateur de
conversion par une fonction nommée. Il n'y aurait plus la conversion
implicite, mais je me démande si ce n'est pas mieux de ne pas l'avoir.
Quand tu passes de Entier à int, tu passes à un niveau moins sécur, plus
dangéreux. Ne serait-ce pas mieux que le programmeur soit obligé à le
préciser ?

Un essai rapide chez moi montre que Sun CC préfère l'opérateur avec
les Entier, et g++ le considère ambigu. En ajoutant ton compilateur,
ça fait trois compilateurs avec trois résultats différents:-). Je
crois que c'est g++ qui a raison.


En fait, j'utilise gcc 3.2.2, mais j'ai pas posté exactement le code
qui me posait problème (qui est un template).


En plus. Tu mélanges des surcharges ambigus, des conversions, et des
templates. Tu cherches des problèmes, non ?

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16



Avatar
Marc Boyer
wrote:
Marc Boyer wrote in message
news:<bgofqv$9q8$...
wrote:
Marc Boyer wrote in message
news:<bglnvr$noc$...

Je suis en train de surcharger + pour un type entier. Soit Entier
le dit type. Il existe une conversion implicite de Entier vers int
(operator int()) et Entier possede un constructeur avec un int
comme paramêtre.


C'est un moyen exceptionnellement efficace à obtenir des ambiguïtés
de surcharge.


Mais ça permet d'initialiser des Entiers à partir d'int, et de
passer des Entiers en paramêtre quand un int est attendu...


Certes. Mais ça fait aussi que dès qu'une expression est mélangée, avec
les deux types, il est ambigu lequel des deux doit servir.


Dans la logique, les operateurs avec vérification, donc
ceux de "Entiers", doivent être prioritaires.

Est-ce que je résoudrais le problème en mettant le constructeur
comme "explict" et en proposant un operateur d'affectation
explicit Entier(int)
Entier(Entier)
Entier operator=(int)
Entier operator=(Entier)
operator int()
ou est-ce que ça apportera d'autres problèmes que je n'anticipe pas
pour le moment ?


Ça voudrait dire que toutes les opérations mixes se font avec des int,
et non des Entier. Tu pourrais, évidemment, fournir tous les opérateurs
mixes ; ce n'est pas si difficile que ça, à l'aide des macros.


De toute façon, je le fais déjà.

J'aurais une tendance à faire l'inverse : à remplacer l'opérateur de
conversion par une fonction nommée. Il n'y aurait plus la conversion
implicite, mais je me démande si ce n'est pas mieux de ne pas l'avoir.
Quand tu passes de Entier à int, tu passes à un niveau moins sécur, plus
dangéreux. Ne serait-ce pas mieux que le programmeur soit obligé à le
préciser ?


Ce me semble l'argument décisif. La marque de l'expérience ;-)
Et en plus, cela implique que toute opération impliquant au
moins un Entier passera par l'appel à l'opérateur entre deux
Entiers. Top.

En fait, j'utilise gcc 3.2.2, mais j'ai pas posté exactement le code
qui me posait problème (qui est un template).


En plus. Tu mélanges des surcharges ambigus, des conversions, et des
templates. Tu cherches des problèmes, non ?


Oui, mais bon... En fait, j'ai des problèmes de taille, et je veux
pouvoir tenter d'utiliser un "petit" entier pour essayer (unsigned char),
et si ça vautre, recompiler avec un unsigned short (voire unsigned int).
Mais c'est clair que si j'avais pas eut fclc++, j'aurais jeté
l'éponge depuis longtemps.

Marc Boyer
--
Lying for having sex or lying for making war? Trust US presidents :-(




Avatar
Marc Boyer
In article , drkm wrote:
Marc Boyer writes:
Oui, mais bon... En fait, j'ai des problèmes de taille, et je veux
pouvoir tenter d'utiliser un "petit" entier pour essayer (unsigned
char), et si ça vautre, recompiler avec un unsigned short (voire
unsigned int).


Un simple typedef n'est-il pas suffisant ? Ce qui éliminerait les
complications suplémentaires apportées par les templates dans la
résolution des surcharges.


J'ai du mal à appréhender le futur, mais je risque d'avoir
des Entier<signed char> par ci, et des Entier<signed int> par
ailleurs, et avec un typedef, j'ai peur qu'il ai du mal.

En ce qui concerne les "complications suplémentaires", oui,
je suis tombé dessus (voir mon autre message).

Marc Boyer
--
Lying for having sex or lying for making war? Trust US presidents :-(


Avatar
drkm
Marc Boyer writes:

wrote:

Marc Boyer wrote in message
news:<bgofqv$9q8$...

En fait, j'utilise gcc 3.2.2, mais j'ai pas posté exactement le
code qui me posait problème (qui est un template).


En plus. Tu mélanges des surcharges ambigus, des conversions, et
des templates. Tu cherches des problèmes, non ?


Oui, mais bon... En fait, j'ai des problèmes de taille, et je veux
pouvoir tenter d'utiliser un "petit" entier pour essayer (unsigned
char), et si ça vautre, recompiler avec un unsigned short (voire
unsigned int).


Un simple typedef n'est-il pas suffisant ? Ce qui éliminerait les
complications suplémentaires apportées par les templates dans la
résolution des surcharges.

--drkm



Avatar
Gabriel Dos Reis
writes:

[...]

| Tu cherches des problèmes, non ?

Non. Des solutions. <g>

-- Gaby