prioridad operadores operador operaciones negacion logicos expresiones cortocircuito condicional aritmeticos aritmeticas c++ comparison-operators

operadores - ¿Tiene C++ un operador de comparación que especifique un rango de valores?(como ''en'' en lenguaje E)?



operadores logicos en c++ (6)

Absolutamente no es idiomático, y probablemente se debe evitar, pero lo más cercano que puede tener (sintácticamente hablando) es usar operadores nombrados . Los operadores nombrados en realidad corresponden a un abuso de la sobrecarga del operador.

enum EnumVariable {a, b, d, g, f, t, k, i}; auto in = make_named_operator( [](int i, std::initializer_list<EnumVariable> const& x) { return std::find(std::begin(x), std::end(x), i) != std::end(x); }); auto vals = { a, g, t, i }; if (g <in> vals) { std::cout << "It works!" << std::endl; }

Here hay un ejemplo de trabajo en Coliru.

Si usa C ++ 14 y lambdas polimórficas, puede hacer que el ejemplo anterior sea más genérico:

auto in = make_named_operator( [](int i, auto const& x) { return std::find(std::begin(x), std::end(x), i) != std::end(x); });

Necesito escribir una condición que verifique si una variable de enumeración en el rango de valores, como se puede hacer en el lenguaje E:

enum EnumVariable {a, b, d, g, f, t, k, i}; if (EnumVariable in [ a, g, t, i]) { ... }

¿Hay una forma mejor en C ++ que preguntar 4 veces if EnumVariable==a or EnumVariable==b etc.?


En C ++ 11, una forma breve de expresar esto es mediante el uso de la sintaxis brace-init para construir un conjunto y llamar a std::set::count para probar si el elemento está presente:

if (std::set<EnumVariable>{a, g, t, i}.count(myVariable)) ...

Un ejemplo compilable:

#include <set> enum EnumVariable {a, b, d, g, f, t, k, i}; int main() { EnumVariable x = t; if (std::set<EnumVariable>{a, g, t, i}.count(x)) { return 0; } return 1; }

Nota sobre la eficiencia: dado que la pregunta sobre un "operador de comparación", la respuesta está escrita con el objetivo de proporcionar una expresión simple bastante breve y de fácil lectura que no requiera una función de utilidad separada. Dado que construye un std::set temporal, no es tan eficiente como una instrucción de switch , que es compilada en pruebas o tablas de salto por todos los compiladores relevantes.


No hay la misma sintaxis compacta, pero puede usar std::find con un std::initializer_list . Por ejemplo,

#include <algorithm> #include <iostream> enum EnumVariable {a, b, d, g, f, t, k, i}; int main() { EnumVariable e = k; auto vals = { a, g, t, i }; // std::initializer_list<EnumVariable> std::cout << std::boolalpha; std::cout << (std::find(vals.begin(), vals.end(), e) != vals.end()) << std::endl; }

Esto puede ser fácilmente envuelto en una función auxiliar que toma el valor de enumeración, la lista, y devuelve un bool . Por ejemplo:

template <typename T> bool is_in(T elem, std::initializer_list<T> range) { for (T i : range) if (i == elem) return true; return false; }

uso:

int main() { EnumVariable ev = a; std::cout << std::boolalpha; std::cout << is_in(ev, {a, g, t, i}) << std::endl; }


Sin embargo, otro enfoque consiste en utilizar una plantilla para especificar la lista para coincidir, lo que para su caso de enum probablemente se conocerá en el momento de la compilación (de lo contrario, incluso el enfoque de switch no es aplicable). Esto permite una notación como:

if (in<a, b, c, d, e, f>(x)) ...

Con la optimización habilitada, esto debería estar en línea y producir algo equivalente a:

a == x || b == x || ...

Implementación a continuación (también ideone ). No he jugado mucho con las plantillas variad, así que las sugerencias son bienvenidas. En particular, cómo hacerlo seguro para el tipo, por lo que se da la enum E { E1 }; enum F { F1 }; enum E { E1 }; enum F { F1 }; , in<E1>(F1) no se compilará (sin limitarlo a un tipo de enum específico).

#include <iostream> using namespace std; template <int First, int... Numbers> inline bool in_impl(int n) { return n == First || in_impl<Numbers...>(n); } template <> inline bool in_impl<int(-1)>(int n) { return false; } template <int... Numbers> inline bool in(int n) { return in_impl<Numbers..., int(-1)>(n); } enum E { E1, E2, E3, E4 }; int main() { std::cout << in<3, 5, 7, 9>(4) << ''/n''; std::cout << in<3, 5, 7, 9>(5) << ''/n''; std::cout << in<E2, E4>(E1) << ''/n''; std::cout << in<E2, E4>(E2) << ''/n''; }

Salida:

0 1 0 1


esto se realiza a menudo / usualmente utilizando campos de bits en una enumeración (claramente, hasta el número de bits de un tipo integral (generalmente 32 bits), que es el tipo predeterminado en la base de una enumeración):

#include <iostream> enum EnumVariable { a=0x0001, b=0x0002, d=0x0004, g=0x0008, f=0x0010, t=0x0020, k=0x0040, i=0x0080 }; inline bool CheckMatch(EnumVariable var, EnumVariable mask) { return (var & mask) != 0; } using namespace std; int main(int argc, char **argv) { EnumVariable mask = EnumVariable(a|g|t|i); EnumVariable x1 = b; EnumVariable x2 = g; cout << "x1: " << (CheckMatch(x1, mask) ? "match" : "no-match") << endl; cout << "x2: " << (CheckMatch(x2, mask) ? "match" : "no-match") << endl; }

que en breve se puede ver como:

if ( x1 & (a|g|t|i) ) { ... }


Al parecer, a varias personas les gustó mi comentario y pidieron publicarlo como respuesta, así que:

En realidad, puede usar el switch para tipos integrales sin break entre algunos valores.

Por ejemplo, su código podría verse como:

enum EnumVariable {a, b, d, g, f, t, k, i}; switch( EnumVariable ) { case a: case g: case t: case i: // do something break; // handler other values };

Esto sería muy eficiente, pero funcionaría solo para tipos integrales , y no para std::string , por ejemplo. Para otros tipos, puede intentar usar algunas de las sugerencias de otras respuestas.

Es un poco largo para escribir, pero es muy, muy eficiente y hace lo que necesitas.