Question

Ce que je veux vraiment est || opérateur =.

old_value = old_value || possible_new_value;
old_value ||= possible_new_value;

La deuxième ligne est une erreur du compilateur (C ++ n'a pas de || = opérateur).

Alors, quelles sont mes autres options?

old_value += possible_new_value;
old_value |= possible_new_value;

Alors que je suis sur le sujet comment ne bool se comporter avec d'autres opérateurs non-booléens?

-
-=
&
&=
...

Je peux vérifier ces empiriquement, mais je suis plus intéressé par ce que dit la norme.

Était-ce utile?

La solution

D'après 4.7 (conversion intégrale), paragraphe 4, « Si le type de destination est bool, voir 4.12. Si le type de source est bool, la false de valeur est convertie à zéro et le true de valeur est convertie en un. » En 4.12, « An rvalue de l'arithmétique, l'énumération, pointeur ou pointeur sur le type d'élément peut être converti en un rvalue de type bool Une valeur zéro, la valeur de pointeur null, ou de la valeur de pointeur d'élément nul est converti en false;. Toute autre valeur converti en true. "

Dans un contexte où opérandes bool ne sont pas autorisés, mais opérandes sont intégrés, la bool sera convertie en un type intégral. Lorsque le résultat entier est stocké dans une variable bool, il sera converti en bool.

Par conséquent, vous serez en mesure d'utiliser + et * comme booléen ou et et, et vous pouvez utiliser | et aussi. Vous ne pouvez pas vous en sortir avec les mélanger, comme (bool1 + bool2) & bool3 donnera false si les trois variables sont true. ((1 + 1) et 1 est égal à 2 et 1, qui est égal à 0, ou faux).

Rappelez-vous que | et || ne fonctionnent pas de manière identique, même ici. | évaluera les deux côtés, puis évaluer la ou bitwise. || évaluera le premier opérande, alors que si cela était faux évaluera le second.

Je ne vais pas discuter des questions de style, mais si je faisais quelque chose comme ça, je serais sûr de le commenter afin que les gens savaient ce que je faisais et pourquoi.

Autres conseils

Le sayeth standard:

4.5-4 "Promotions intégrale"

  

Un rvalue de type bool peut être   converti en un rvalue de type int,   avec de faux devenir nul et vrai   le devenir.

5.17-7 "Opérateurs d'affectation"

  

Le comportement de l'expression de la   former E1 = E2 op est équivalent à E1 =   E1 op E2 sauf que E1 est évalué   juste une fois. Dans + = et - =, E1 doit   soit être de type arithmétique ou une   pointeur sur un éventuellement cvqualified   complètement défini type d'objet. Dans tout   d'autres cas, E1 ont arithmétique   le type.

4.12-1 "conversions" booléennes

  

Un rvalue de l'arithmétique, le dénombrement,   pointeur ou pointeur sur le type d'élément peut   être converti en un rvalue de type   bool. Une valeur de zéro, le pointeur null   la valeur, ou la valeur de pointeur d'élément nul est   converti en faux; toute autre valeur est   converti en vrai.

Cela signifie donc que

b1 += b2

Où b1 et b2 sont booléennes sera équivalent à

b1 = b1 + b2

b1 et b2 seront promus 0/1 entiers, puis reconverti en booléennes sur la règle que tout autre que 0 est vrai.

Ainsi, la table de vérité est

            true   false
true     true   true
false    true   false

so + = ne travaillent en fait comme || = conformément à la norme. Cependant, ce sera probablement source de confusion d'autres programmeurs, donc je l'éviter encore.

Pouvez-vous utiliser l'opérateur ternaire?

  

old_value = !old_value ? possible_new_value : old_value;

Ne pas utiliser |= et &= avec bools. Ils peuvent travailler la plupart du temps, mais il est encore mal. Habituellement, le type bool est juste un glorifiée int ou char. Dans le code plus que j'ai travaillé avec, BOOL est juste typedef int ou char. Dans ce cas, vous pouvez obtenir la mauvaise réponse en quelque sorte si les bits ont été manipulés (par exemple, 1&2 est 0 (faux)). Et je ne suis pas sûr, mais je pense que le résultat des opérateurs binaires va être un entier, même pour bools.

if (!old_value)
    old_value = possible_new_value;

Ceci est un équivalent direct de l'état d'origine. Il pourrait générer un code plus simple car il attribuera pas toujours à old_value -. Mais je ne s'attendre à la différence de performance pour être facilement mesurable dans un grand programme

Une différence est que les opérateurs logiques tels que || garantir l'ordre d'évaluation et de fournir un court-circuit, où les opérateurs sages bits et l'arithmétique ne le font pas.

Je crois que le compilateur traitera les opérateurs non logiques en convertissant les valeurs numériques bools à (0, 1) en appliquant l'opérateur et la conversion en arrière. Ces conversions sont strictement définies par la norme, par exemple:.

  

Un rvalue de l'arithmétique, l'énumération, pointeur ou pointeur sur le type d'élément peut être converti en un rvalue de type bool. Une valeur zéro, la valeur de pointeur null, ou de la valeur de pointeur d'élément nul est converti en false toute autre valeur est convertie en vrai.

Nasty macro carriole:

#define UPDATE(x) x = x

UPDATE(old_value) || possible_new_value;

Mais je ne recommande pas du tout. Les macros de ce genre sont une très mauvaise idée pour plusieurs raisons.

Une fonction plus sain d'esprit, mais sans court-circuit:

bool set_or(bool &old, bool value) {
  return (old = old || value);
}

...

bool v = false;
set_or(v, true);

Je crois que la norme définit explicitement vrai et faux comme 1 et 0, donc vous pouvez utiliser en toute sécurité les opérateurs sur les valeurs de bits bool. D'autres types qui pourraient être implicitement traités comme bools dans un autre contexte doivent être explicitement convertis pour que cela fonctionne de manière fiable.

Je l'ai vu le compilateur de Microsoft générer un avertissement laid à chaque fois que vous faites cela, parce qu'il pense qu'il ya un danger pour convertir implicitement le résultat int retour à bool.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top