c++ arrays casting boolean

c++ - ¿Puedo verificar una pequeña variedad de bools de una vez?



arrays casting (5)

... Y para la respuesta obligatoria "roll your own", podemos proporcionar una función simple "o" similar a cualquier array bool[N] , así:

template<size_t N> constexpr bool or_all(const bool (&bs)[N]) { for (bool b : bs) { if (b) { return b; } } return false; }

O más concisamente

template<size_t N> constexpr bool or_all(const bool (&bs)[N]) { for (bool b : bs) { if (b) { return b; } } return false; }

Esto también tiene el beneficio de cortocircuito como || , y ser optimizado por completo si es calculable en tiempo de compilación.

Aparte de eso, si desea examinar la idea original de bool[N] de tipo punzonado a otro tipo para simplificar la observación, le recomiendo que no lo haga verlo como char[N2] lugar, donde N2 == (sizeof(bool) * N) . Esto le permitiría proporcionar un visor de representación simple que puede escalar automáticamente al tamaño real del objeto visto, permitir la iteración sobre sus bytes individuales y permitirle determinar más fácilmente si la representación coincide con valores específicos (como, por ejemplo, cero o no -cero). No estoy del todo seguro si tal examen invocaría cualquier UB, pero puedo decir con certeza que la construcción de cualquier tipo de este tipo no puede ser una expresión constante viable, debido a que requiere una reinterpretación emitida a char* o unsigned char* o similar (ya sea explícitamente o en std::memcpy() ), y por lo tanto no podría optimizarse tan fácilmente.

Había una pregunta similar here , pero el usuario en esa pregunta parecía tener una matriz o vector mucho más grande. Si tengo:

bool boolArray[4];

Y quiero verificar si todos los elementos son falsos, puedo verificar [0], [1], [2] y [3] ya sea por separado, o puedo recorrerlo. Como (hasta donde yo sé) falso debería tener el valor 0 y cualquier otra cosa que no sea 0, es cierto, pensé simplemente en hacer:

if ( *(int*) boolArray) { }

Esto funciona, pero me doy cuenta de que se basa en que bool es un byte e int cuatro bytes. Si lanzo a (std :: uint32_t), ¿estaría bien o sigue siendo una mala idea? Simplemente tengo 3 o 4 bools en una matriz y me preguntaba si esto es seguro, y si no, si hay una mejor manera de hacerlo.

Además, en el caso de que termine con más de 4 bools pero menos de 8, ¿puedo hacer lo mismo con std :: uint64_t o unsigned long long o algo así?


Como πάντα ῥεῖ notó en los comentarios, std::bitset es probablemente la mejor manera de lidiar con eso de manera libre de UB.

std::bitset<4> boolArray {}; if(boolArray.any()) { //do the thing }

Si desea apegarse a las matrices, puede usar std::any_of , pero esto requiere (posiblemente peculiar para los lectores) el uso de functor que simplemente devuelve su argumento:

bool boolArray[4]; if(std::any_of(std::begin(boolArray), std::end(boolArray), [](bool b){return b;}) { //do the thing }

Escribir 4 bool s a int puede ser una mala idea: no puede estar seguro del tamaño de cada uno de los tipos. Probablemente funcionará en la mayoría de las arquitecturas, pero std::bitset está garantizado para funcionar en todas partes, bajo cualquier circunstancia.



Puede usar std::bitset<N>::any :

Cualquiera devuelve true si alguno de los bits se establece en true , de lo contrario false .

#include <iostream> #include <bitset> int main () { std::bitset<4> foo; // modify foo here if (foo.any()) std::cout << foo << " has " << foo.count() << " bits set./n"; else std::cout << foo << " has no bits set./n"; return 0; }

Live

Si desea devolver true si todos o ninguno de los bits están activados, puede usar std::bitset<N>::all o std::bitset<N>::none respectivamente.


Varias respuestas ya han explicado buenas alternativas, particularmente std::bitset y std::any_of() . Escribo por separado para señalar que, a menos que sepa algo que no sabemos, no es seguro escribir un juego de palabras entre bool e int de esta manera, por varias razones:

  1. int podría no tener cuatro bytes, como lo han señalado múltiples respuestas.
  2. MM señala en los comentarios que bool podría no ser un byte. No conozco ninguna arquitectura del mundo real en la que este haya sido el caso, pero sin embargo es legal. (Probablemente) no puede ser más pequeño que un byte a menos que el compilador esté haciendo una trampa muy elaborada para esconder la pelota con su modelo de memoria, y un bool de varios bytes parezca bastante inútil. Sin embargo, tenga en cuenta que un byte no necesita ser 8 bits en primer lugar.
  3. int puede tener representaciones de trampa . Es decir, es legal que ciertos patrones de bits causen un comportamiento indefinido cuando se envían a int . Esto es raro en las arquitecturas modernas, pero podría surgir en (por ejemplo) ia64 , o cualquier sistema con ceros firmados.
  4. Independientemente de si tiene que preocuparse por cualquiera de los anteriores, su código viola la estricta regla de alias , por lo que los compiladores son libres de "optimizarlo" bajo el supuesto de que los bools y el int son objetos completamente separados con vidas que no se superponen. Por ejemplo, el compilador podría decidir que el código que inicializa la matriz bool es un almacén muerto y eliminarlo, porque los bools "deben haber" dejado de existir * en algún momento antes de desreferenciar el puntero. También pueden surgir situaciones más complicadas relacionadas con la reutilización de registros y la reordenación de carga / almacenamiento. Todas estas infelicidades están expresamente permitidas por el estándar C ++, que dice que el comportamiento no está definido cuando te involucras en este tipo de castigos.

Debe usar una de las soluciones alternativas proporcionadas por las otras respuestas.

* Es legal (con algunas calificaciones, particularmente con respecto a la alineación) reutilizar la memoria a la que apunta boolArray lanzándola a int y almacenando un número entero, aunque si realmente desea hacer esto, debe pasar boolArray través de std::launder boolArray si quieres leer el int resultante más tarde. En cualquier caso, el compilador tiene derecho a asumir que ha hecho esto una vez que ve la lectura, incluso si no llama al blanqueador.