2009-08-18 10 views
5

Lo que realmente quiero es un operador || =.comportamiento de bool con operadores no booleanos

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

La segunda línea es un error del compilador (C++ no tiene un operador || =).

¿Cuáles son mis otras opciones?

old_value += possible_new_value; 
old_value |= possible_new_value; 

Mientras que estoy en el tema ¿cómo se comporta bool con otros operadores no booleanos?

- 
-= 
& 
&= 
... 

Puedo verificar esto empíricamente, pero estoy más interesado en lo que dice la norma.

Respuesta

12

Según 4,7 (conversiones integral), párrafo 4, "Si el tipo de destino es bool, ver 4.12.Si el tipo de fuente es bool, el valor false se convierte a cero y el valor true se convierte en uno. "En 4.12," Un valor de aritmética, enumeración, puntero o puntero al tipo de miembro se puede convertir a un valor de tipo r bool. Un valor cero, valor de puntero nulo o valor de puntero de miembro nulo se convierte a false; cualquier otro valor se convierte a true."

En un contexto en bool operandos no son permitidos pero operandos integrales están, la bool serán convertidos a un tipo integral. Cuando el resultado entero se almacena en una variable bool, será . puede convertir en bool

Por lo tanto, usted será capaz de utilizar + y * como booleano OR y AND, y se puede usar | & y también que no puede salirse con la mezcla de ellos, como (+ Bool1 Bool2.) & bool3 dará false si las tres variables son true. ((1 + 1) & 1 es 2 & 1, que es 0 o falso.)

Recuerde que | y || no funcionan de manera idéntica, incluso aquí. | evaluará ambos lados, y luego evaluará el bit a bit o. || evaluará el primer operando, entonces solo si eso fue falso evaluará el segundo.

No voy a discutir los temas estilísticos aquí, pero si hiciera algo así, me aseguraría de comentarlo para que la gente supiera lo que estaba haciendo y por qué.

+0

increíble, gracias. Yo votaría dos veces si pudiera –

+0

+1 por citar el estándar (y respondiendo la pregunta), mientras también agrego el comentario sobre el estilo – Gabe

0

No utilice |= y &= con bools. Pueden trabajar la mayor parte del tiempo, pero todavía está mal. Por lo general, el tipo bool es solo un int glorified o char. En el código anterior con el que he trabajado, BOOL simplemente está escrito en int o char. En estos casos, puede obtener la respuesta incorrecta si de alguna manera los bits han sido manipulados (por ejemplo, 1&2 es 0 (falso)). Y no estoy seguro, pero creo que el resultado de los operadores bit a bit será un int, incluso para bools.

+0

thoughts on + =? –

+3

Si ambas variables se declaran como '' bool' ', ¿bajo qué circunstancias (aparte de un compilador roto, o un compilador no estándar, también conocido como pre-estándar), ¿van a salir mal? –

+0

si alguna vez se pasa como un vacío * o algo así, y tiene una API que usa el tipo como int, no se le puede garantizar que siempre usarán "1" para verdadero, a diferencia de cualquier otro no -zero entero. – Kip

0
if (!old_value) 
    old_value = possible_new_value; 

Esto es un equivalente directo de la condición original. Puede generar código más simple, ya que no siempre se asignará a old_value, pero no esperaría que la diferencia de rendimiento se pueda medir fácilmente en un programa grande.

0

Una diferencia es que los operadores lógicos como || garantizan el orden de evaluación y proporcionan un cortocircuito, donde los operadores de bits y aritméticos no lo hacen.

Creo que el compilador tratará a los operadores no lógicos convirtiendo los bools en valores numéricos (0, 1) aplicando el operador y convirtiendo de nuevo. Estas conversiones están estrictamente definidas por el estándar, por ejemplo:

Un valor de aritmética, enumeración, puntero o puntero al tipo de miembro se puede convertir a un valor r de tipo bool. Un valor cero, un valor de puntero nulo o un valor de puntero de miembro nulo se convierte en falso, cualquier otro valor se convierte en verdadero.

1

¿Podría usar el operador ternario?

old_value = !old_value ? possible_new_value : old_value;

+0

por qué sería preferible al más corto 'old_value = old_value || new_value; '? – Kip

+1

Parece que leí la pregunta incorrectamente :) No hay ninguna razón para hacer eso en vez de 'old_value = old_value || new_value; ', especialmente porque este último es más legible. – Cinder6

0

desagradable macro hackery:

#define UPDATE(x) x = x 

UPDATE(old_value) || possible_new_value; 

Pero no recomiendo esto en absoluto. Las macros como esta son una muy mala idea por varias razones.

Una función más sano, pero sin el cortocircuitos:

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

... 

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

Por supuesto, esto solo funciona cuando x es una variable, y solo falla obviamente cuando x no termina con un valor l, y depende crucialmente de construir una expresión medio dentro y fuera de la macro. Ewwwww. –

+0

Esta macro fallará si la evaluación de '' posible_nuevo_valor' tiene un efecto secundario. –

+0

Si falla depende de cuál debería ser la semántica propia de '|| ='. No estoy seguro de si el cortocircuito estaría destinado allí o no. – sth

4

El sayeth estándar:

4.5-4 "Promociones integral"

Un valor p de tipo bool se puede convierte en un valor p de tipo int, con falso convertirse en cero y verdadero convirtiéndose en uno.

5.17-7 "Operadores de asignación"

El comportamiento de una expresión de la forma E1 op = E2 es equivalente a E1 = E1 op E2 E1 excepto que se evalúa solamente una vez. En + = y - =, E1 deberá tener un tipo aritmético o ser un apuntando a un tipo de objeto posiblemente definido como completamente definido. En todos los demás casos , E1 tendrá un tipo de aritmética .

4.12-1 "booleanas Conversiones"

Un valor p de la aritmética, enumeración, puntero, o puntero a tipo de miembro puede ser convertido en un valor p de tipo bool. Un valor nulo, puntero nulo, o el valor del puntero de miembro nulo es convertido a falso; cualquier otro valor es convertido a verdadero.

Así que esto significa que

b1 += b2 

Cuando b1 y b2 son booleano será equivalente a

b1 = b1 + b2 

Y b1 y b2 será promovido a 0/1 enteros, y luego se convierte volver a booleano en la regla de que cualquier cosa que no sea 0 es verdadero.

Así la tabla de verdad es

 
      true false 
true  true true 
false true false 

por lo + = de hecho funciona como || = de acuerdo a la norma. Sin embargo, esto probablemente confundirá a otros programadores, así que lo evitaría aún.

+0

Niza inclusión de 5.17-7. –

+0

+1 para citar el estándar, y para el desglose explícito de + =, y para el consejo de evitar + =. –

0

Creo que el estándar define explícitamente verdadero y falso como 1 y 0, por lo que puede usar de forma segura operadores bit a bit en los valores bool. Otros tipos que podrían tratarse implícitamente como bools en otro contexto deberían convertirse explícitamente para que esto funcione de manera confiable.

He visto que el compilador de Microsoft genera una advertencia desagradable cada vez que haces esto, porque cree que existe el peligro de convertir implícitamente el resultado int en bool.

Cuestiones relacionadas