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.
La biblioteca estándar tiene lo que necesita en forma de algoritmos std :: all_of, std :: any_of, std :: none_of .
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;
}
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:
-
int
podría no tener cuatro bytes, como lo han señalado múltiples respuestas. -
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. -
int
puede tener representaciones de trampa . Es decir, es legal que ciertos patrones de bits causen un comportamiento indefinido cuando se envían aint
. Esto es raro en las arquitecturas modernas, pero podría surgir en (por ejemplo) ia64 , o cualquier sistema con ceros firmados. - 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.