OVH Cloud OVH Cloud

evaluation avec "? "...un vestige de C ? ex: b1 ? "..." : "...."

23 réponses
Avatar
heinquoi
bjr,

j'ai dans un exemple un programme qui contient la ligne :
cout << endl << "le nombre 11 etait " << (b2 ? "TROUVE" : "NON TROUVE") <<
endl;

je intéresse surtout à (b2 ? "TROUVE" : "NON TROUVE")
est ce que opérateur évaluation "?" est un vestige de C ?

si je remplace ce morceau par
( if b2 "TROUVE" else "NON TROUVE") cela ne fonctionne pas, pourtant il
s'agit d'evaluation sur b2
hormis le fait que cette écriture lorsqu'elle est fréquente est obscure et
limite 'incantatoire' qu'elle est sont intérêt et pourquoi fonctionne t elle
ou un if ne fonctionne pas?
--
Cordialement,
Heinquoi

10 réponses

1 2 3
Avatar
tib.motuelle
James Kanze wrote in message news:...
Je ne sais pas en ce qui concerne les autres, mais je m'en sers assez
librement.


Je l'utilise aussi beaucoup et, correctement indenté, je trouve ca
très lisible.

Si l'idée importante derrière un bout de code, c'est que la
valeur x soit affectée, et non qu'on a une condition, je le trouve plus
claire d'écrire :

x = ( condition
? a
: b ) ;

que :

if ( condition ) {
x = a ;
} else {
x = b ;
}


C'est également indispensable lorsque l'on veut initialiser une
référence ou un objet const à une chose ou une autre selon une
condition (il y a des alternatives mais elles sont nettement plus
lourdes).

--
Bertrand.

Avatar
Twxs

En tous cas, sur mon compilateur,
std::cout<<(0?3:4.567);
retourne 4.567 et non pas 4 (comme ce serai le cas avec une conversion
en int)



verifie le code assembleur genere par le compilateur, il sais a la
compilation que le test est tjs faux il remplace ca directement par 4.56
enfin sous visual

Twxs

Avatar
Pierre Maurette
Twxs typa:



En tous cas, sur mon compilateur,
std::cout<<(0?3:4.567);
retourne 4.567 et non pas 4 (comme ce serai le cas avec une conversion
en int)



verifie le code assembleur genere par le compilateur, il sais a la
compilation que le test est tjs faux il remplace ca directement par 4.56
enfin sous visual
C'est beaucoup plus simple que ça. Il s'agit d'une expression

constante, expression réduite à l'opérateur ternaire nourri
d'opérandes constantes immédiates. Elle est donc remplacée à la
compilation par son résultat, pas d'optimisation là-derrière. Si la
norme l'exigeait, ce résultat serait 4. Mais ce n'est pas le cas.
--
Pierre


Avatar
kanze
Twxs wrote in message
news:<40db47e7$0$4560$...

En tous cas, sur mon compilateur,
std::cout<<(0?3:4.567);
retourne 4.567 et non pas 4 (comme ce serai le cas avec une
conversion en int)


verifie le code assembleur genere par le compilateur, il sais a la
compilation que le test est tjs faux il remplace ca directement par
4.56 enfin sous visual


Et si la norme exigeait que le résultat soit 4, une telle optimization
serait une erreur dans le compilateur.

En fait, la norme n'exige rien comme tel. Tout au contraire -- un
compilateur qui renvoyait 4 serait erroné.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
kanze
Pierre Maurette wrote in message
news:...
James Kanze typa:

"heinquoi" <nospam* writes:

|> j'ai dans un exemple un programme qui contient la ligne :
|> cout << endl << "le nombre 11 etait " << (b2 ? "TROUVE" : "NON TROUVE") <<
|> endl;

|> je intéresse surtout à (b2 ? "TROUVE" : "NON TROUVE") est ce que
|> opérateur évaluation "?" est un vestige de C ?

Dans le même sens que l'opérateur de '+' est un vestige de C ?

|> si je remplace ce morceau par ( if b2 "TROUVE" else "NON TROUVE")
|> cela ne fonctionne pas, pourtant il s'agit d'evaluation sur b2
|> hormis le fait que cette écriture lorsqu'elle est fréquente est
|> obscure et limite 'incantatoire' qu'elle est sont intérêt et
|> pourquoi fonctionne t elle ou un if ne fonctionne pas?

Parce qu'un if, c'est une instruction de contrôle de flux, et ?:,
c'est un opérateur. On aurait pu imaginer qu'le même syntaxe sert
dans les deux cas, mais ce n'est pas le cas en C ni en C++ (ni en
Java, ni en Objective C, ni en ...).

Je ne sais pas en ce qui concerne les autres, mais je m'en sers assez
librement. Si l'idée importante derrière un bout de code, c'est que
la valeur x soit affectée, et non qu'on a une condition, je le trouve
plus claire d'écrire :

x = ( condition
? a
: b ) ;

que :

if ( condition ) {
x = a ;
} else {
x = b ;
}


Et si c'est:

int x = (condition ? a : b);

il faudrait faire:

int x;
if(condition)
{
x = a;
}
else
{
x = b;
}


C'est une raison supplémentaire pour utiliser ?:. Dans le cas d'int,
passons, mais que faire pour l'initialisation de
MaClassSansCtorParDefaut ?

En fait, j'utilise aussi les ?: beaucoup des les listes
d'initialisation, dans les constructeurs, pour la même raison :

MaClasse::MaClasse(
int param1,
int param2 )
: MaBase( param1 > param2 ? param1 : param2 )
{
}

Dans ces cas-là, on n'a de toute façon pas le choix. Mon but était de
montrer que même quand on a le choix, l'utilisation de ?: peut dans
certains case être préférable à if ... else.

Ça va plus loin, l'opérateur ? pouvant s'utiliser à la place d'une
rvalue (éventuellement temporaire), on arrive à des écritures à la
fois plus compactes et pour moi plus lisibles :

y = fonct(10, (condition ? a : b));


Tout à fait. Ce qui importe ici, ce n'est pas la condition, c'est
l'affectation de la variable y avec le résultat d'un appel à la fonction
fonct.

ou l'exemple de la question de départ:

std::cout << (condition ? "VRAI" : "FAUX") << std::endl;

En revanche, et bien que ce soit possible semble-t-il, remplacer un if
par un ? me paraît non naturel et à éviter :

(condition ? std::cout<<100 : std::cout<<200); //NON

Je veux dire par là que si le but est l'évaluation et non
l'affectation, le if() est LA solution.


Tout à fait. Quand l'important, c'est la selection, on veut le mot clé
à gauche, pour l'indiquer. Quand l'important, c'est l'affectation, on
veut que l'affectation soit la première chose qu'on voit en lisant la
ligne, et non la condition.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Fabien LE LEZ
On 25 Jun 2004 04:46:48 -0700, :

MaClasse::MaClasse(
int param1,
int param2 )
: MaBase( param1 > param2 ? param1 : param2 )
{
}

Dans ces cas-là, on n'a de toute façon pas le choix.


: MaBase (std::max (param1, param2))


--
schtroumpf schtroumpf

Avatar
kanze
Fabien LE LEZ wrote in message
news:...
On 23 Jun 2004 23:44:54 +0200, James Kanze :

Si l'idée importante derrière un bout de code, c'est que la valeur x
soit affectée, et non qu'on a une condition, je le trouve plus claire
d'écrire :

x = ( condition
? a
: b ) ;


J'aimerais savoir ce que tu penses de :

ifstream fichier (condition ? "input1.txt" : "input2.txt");

Je précise ma question : le fait de se passer d'une variable
"nom_de_fichier" (ce qui est rendu possible par le fait qu'on utilise
"?:" et pas "if") est-il (d'après toi) un élément de clarification ou
d'obfuscation ?


Tout dépend du contexte. J'utilise assez souvent des choses du genre :

std::ifstream fichier( nom == NULL
? nomParDefaut
: nom ) ;

Évidemment, ce n'est valable que dans la mésure que la condition et les
alternatives sont simple. La plupart du temps, j'ai plutôt quelque chose
du genre :

std::istream* source = NULL ;
if ( nom == NULL || strcmp( nom, "-" ) == 0 ) {
source = &std::cin ;
} else {
ifstream* tmp = new ifstream( nom ) ;
if ( *tmp ) {
source = tmp ;
} else {
error( std::string( "cannot open " ) + nom ) ;
delete tmp ;
}
}
if ( source != NULL ) {
process( *source ) ;
if ( source != &std::cin ) {
delete source ;
}
}

Je ne vois pas trop comment faire l'équivalent avec ?:. En revanche, je
verrais bien dans certains cas le contenu du premier else dans une
fonction à part, avec comme initialisation de source :

std::istream* source = ( nom == NULL || strcmp( nom, "-" ) == 0
? &std::cin
: getNewIFStream( nom ) ) ;

Parce qu'en fin de compte, l'important dans l'histoire, c'est bien que
source est définie ET initialisée.

(Mais en fait, j'ai un streambuf filtrant qui s'occupe de tout ça:-).
Voir MutlipleFileInputStream à mon site.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
heinquoi
a écrit dans le message de
news:

Les règles sont bien plus compliquées que ça. Ni l'une ni l'autre des
expressions n'est privilégées, et les compilateur essaie de trouver un
type commun. Mais on limite le champs de ses recherches, quand même. En
gros :

- D'abord, il y a certaines conversions « standard » qui sont faites
systèmatiquement sur les deux types -- du genre tableau en pointeur.

- Des conversions arithmétiques habituelles peuvent être appliquées
aux deux côtés, si nécessaire.

- Si une des expressions donne un pointeur, et l'autre est une
constante integrale de valeur 0, la constante integrale est
convertie en pointeur nul.

- Si les types des deux expressions sont tous les deux des pointeurs
ou des références à des classes, et une des classes est une classe
de base de l'autre, le pointeur au type dérivé est converti en
pointeur au type de base.

- Il y a le cas spécial où une des expressions est une expression de
throw (qui a le type void) -- le type final est le type de l'autre
expression (qui serait évidemment le seul qui pourrait servir comme
résultat).

Il y a d'autres cas aussi, mais je crois qu'ils servent moins souvent.

Il y a un cas dont l'absense me frustre de temps en temps : si les types
des deux expressions sont des pointeurs à des classes, et les deux
classes ont une classe de base en commun, ça ne marche pas. Donc, des
choses comme :

Base* pb = condition ? new Derived1 : new Derived2 ;

ne marche pas ; il faut explicitement convertir au moins un des
expressions en type Base*. L'une ou l'autre (ou les deux), ça ne fait
rien.

Dans ton exemple, le résultat est "cout << 3" si vrai "cout << (int)
4.568"


si faux


Dans son exemple, le cout était en dehors de l'expression
conditionnelle. Et le type de l'expression conditionnelle, c'était bien
double, et non int, c-à-d que son expression totale était l'équivalent
de :

cout << (b1 ? static_cast< double >( 3 ) : 4.568) ;


tout a fait d'accord apres experimentation le retour de b1 ? 3 : 4.568 est
tjrs un double.


(C'est le deuxième point cité ci-dessus : les conversions arithmétiques
habituelles.) Dans son premier exemple, il y avait aussi des
conversions, puisque le type de la première expression était char
const[7], et celui de la deuxième char const[11]. Ici, c'est le premier
point qui s'applique ; on verrait bien la différence en faisant :

sizeof( b2 ? "TROUVE" : "NON TROUVE" )

(qui ne vaut ni sizeof( "TROUVE" ) ni sizeof( "NON TROUVE" ), sauf cas
accidentel).


ici, d'apres mes experimentations avec VC++6 et IntelC++8 , la conversion
des const chaines de caractère se fait en pointeur sur char ( char*).ce qui
semble logique puique ce sont 2 str, et seul leur lgueur varie. Cela semble
d'ailleurs une conversion implicite tres frequentes.

--
Cordialement,
Heinquoi


Avatar
heinquoi
bjr,

Merci bcp à qui m'a offert une réponse clair et très
précise dans
http://groups.google.fr/groups?hl=fr&lr=&ie=UTF-8&frame=right&thb6458b9df92b495&seekm=qeind0186cfmpe4menn4d2gjr4s814fjok%404ax.com#link8
. J'ai d'ailleurs fait quelques expérimentation et me suis replongé ds 'le
langage c++' de bjarne Stroustrup ( qui bien qu'un peu plus précis que
me semble parfois bcp moins clair !).
--
Cordialement,
Heinquoi
Avatar
Gabriel Dos Reis
Loïc Joly writes:

| wrote:
|
|
| > Il y a un cas dont l'absense me frustre de temps en temps : si les types
| > des deux expressions sont des pointeurs à des classes, et les deux
| > classes ont une classe de base en commun, ça ne marche pas. Donc, des
| > choses comme :
| > Base* pb = condition ? new Derived1 : new Derived2 ;
| > ne marche pas ; il faut explicitement convertir au moins un des
| > expressions en type Base*. L'une ou l'autre (ou les deux), ça ne fait
| > rien.
|
| Tu sias pour quelle raison ? Est-ce simplement un oubli, ou y avait-il
| une difficulté ?

D'après ce que je sais, ce n'est pas un oubli. C'est le résultat d'un
principe général. Le principe général est que l'un des opérandes est
converti au type de l'autre. Donc, il n'y a pas de notion de chercher
un type holistique auquel on devrait convertir les deux opérandes.

-- Gaby
1 2 3