2012-01-10 11 views
40

Una pregunta todo para la diversión/curiosidad: ¿Cómo escribir un bucle for en C++ que iterar sobre dos valores de una bool (es decir true y false) , utilizando solo operaciones con bool (es decir, sin conversiones a otros tipos)?Cómo escribir un 'bucle for` sobre los valores bool (falso y verdadero)

El fondo es que quería comprobar cuántas soluciones existe para una ecuación como (A && B) || (!B && !C && !D) == true, y empecé a escribir algo como for (bool A=false; ??? ; ++A) for (bool B=false; ...) etc pero inmediatamente quedé atrapado por ??? - es decir, lo que sería la condición para continuar el bucle? Por supuesto que lo reescribí para usar int, y también sé que un bucle do ... while funcionará, pero me entró curiosidad si alguna vez es posible escribir un bucle for. Y puesto que lo que no parecen tener una respuesta, decidí pedir :)


Actualización: tenga en cuenta que una variante de "obvia" for(bool A=false; !A; A=true) sugirió en al menos dos respuestas acaban de ser eliminadas sólo ejecutar una iteración, porque para el segundo, la condición !A se convierte en false y el bucle finaliza.

Después de reflexionar, creo que es imposible hacerlo en C++ 03 sin una segunda variable o una construcción basada en un puntero como lo sugiere Dietmar Kühl. La condición debe probarse tres veces en una ejecución deseada, por lo que dos valores de un bool simplemente no son suficientes. Y el bucle do-while funciona porque la primera iteración se ejecuta incondicionalmente, la condición solo se verifica dos veces y, por lo tanto, se puede usar un valor bool para seleccionar entre continuar y salir.

+2

¡Es sorprendente cuán rápido se eliminan las respuestas incorrectas! –

+1

Sí, ¿no lo odias cuando hacen esto? Me parece una buena pregunta. Subí. –

+0

Porque este sitio no es por diversión/curiosidad. Preguntas reales! PD: No, no fui yo, también tengo curiosidad. –

Respuesta

48

En C++ 11: for (bool b : { false, true }) { /* ... */ }


Aquí hay una versión de C++ 03: (. Utilice uno o ab)

for (bool a = true, b = false; b != a; a = a && b, b = !b) { /*...*/ } 

+1

Esa es una versión interesante con la lista de inicializadores. – Xeo

1

Esta funciona , también:

for (bool a = false, b = false; a == b; b = !b, a = a || b) { } 

(tipo de solución invertida que @ KerrekSB de)

6

cuando se está restringido a C++ 2003 que podría utilizar un enfoque más o menos equivalente al enfoque C++ 2011;

{ 
    bool const bools[] = { false, true }; 
    for (bool const* it(bools); it != std::end(bools); ++it) { 
     bool a(*it); 
     use(a); 
    } 
} 

Posiblemente empacado en una macro. También puede utilizar

for (bool a: { false, true }) { 
    use(a); 
} 
+0

Creo que podrías empacar ese conjunto en la parte de declaración del ciclo for. Aunque no estoy seguro – Xeo

+0

Tu magia 2 contradice toda la idea. – Wolf

+1

@ Wolf: la respuesta fue escrita en 2012. Supongo que pasado de mí no asumí que C++ 11 estuviera generalmente disponible (aunque descubrí la funcionalidad necesaria para implementar 'std :: end()' -1998. –

2

Uno más para C++ 03:

for(bool a = false, b = true; b; a = !a, b = a) 

Utilice b.

4
for (int a = 0; a <= 1; a++) 
    doStuff(a ? true : false); 

Y olvídate de la restricción "no hay conversiones a otros tipos" :) Al final del día, la claridad es más importante que las restricciones artificiales. Cinco años después leerás tu propio código y te preguntarás "¿qué diablos estaba pensando? ¿Es esto una especie de concurso de ofuscación?"

+0

Si usa' char'/'uint8_t' en lugar de' int', hay una buena posibilidad de que compilen en el mismo tipo de datos subyacente y le da un casting de costo cero. –

+0

@ SlippD.Thompson Depende de 'doStuff' si' int' es eficiente o no. – Wolf

4
a = true; 
do { 
    use(a); 
    a = !a; 
} while (!a); 

bien, así que no es un para bucle, pero yo diría que es más fácil de leer que cualquiera de las sugerencias de bucle (que no sean el enfoque C++ 11, por supuesto.)

+0

Para hacer que 'continue' funcione dentro del ciclo como se esperaba:' a = false; hacer {...} mientras (a =! a); '. Valor inicial en una variable/constante: 'a = init; do {...} while (init! = (a =! a)); ' – adf88

2

Esta respuesta aborda el C++ 03, única solución de una sola variable "imposible"

en primer lugar, vamos a confirmar que ninguna expresión aritmética determinista confiar sólo en una variable de entrada única puede ser cierto para ambas entradas, pero luego no true,false para un tercer valor que debe ser uno de true o false .

Sin embargo, podemos "hacer trampa". Sin embargo, te imploro que demuestres que estoy engañando.

#include <iostream> 

using namespace std; 

int main() { 
    for (bool b = false; *((char*)&b) != 2; *((char*)&b) += 1) { 
     cout << "bool " << b << endl; 
    } 
} 

Esto ciertamente parece como un comportamiento indefinido. C++ 03 es un poco unclear about it. Sin embargo, sizeof siempre debe ser al menos 1 (con una excepción no estándar para arreglos var-len de 0-longitud). Además, como estamos seguros de que cada char tiene al menos 8 bits, podemos usar el segundo para nuestro contador.

De hecho, para hacer esto tenemos que fallar el determinismo (no se puede sin renunciar a la garantía que iteramos más de false, true exactamente una vez) o nuestro sistema de tipo restrictivo.

0

Sé que solicitó una solución sin conversión a otro tipo, pero supongo que quiere decir "sin conversión a otro tipo no asignado". Aquí hay una respuesta que ofrece un objeto que reemplaza bool en este caso específico.

struct IterableBool 
{ 
    bool b; 
    bool out_of_scope; 
    IterableBool() : b(false), out_of_scope(false) {} 
    IterableBool(bool b_) : b(b_), out_of_scope(false) {} 
    IterableBool(IterableBool ib) : b(ib.b), out_of_scope(ib.out_of_scope) {} 
    operator bool() { return this->b; } 
    bool in_scope() const { return !this->out_of_scope; } 
    IterableBool& operator ++() 
    {      
    this->out_of_scope = this->b; 
    this->b = true; 
    return *this; 
    } 
    IterableBool operator ++ (int) 
    { 
    IterableBool copy = *this; 
    ++(*this); 
    return copy; 
    } 
    IterableBool& operator --() 
    { 
    this->out_of_scope = !this->b; 
    this->b = false; 
    return *this; 
    } 
    IterableBool operator -- (int) 
    { 
    IterableBool copy = *this; 
    --(*this); 
    return copy; 
    } 
}; 

// Usage : 
for(IterableBool ib = false; ib.in_scope(); ++ib) 
    do_stuff((bool)ib); 
Cuestiones relacionadas