2010-12-09 9 views
7

¿Hay una forma rápida/en línea de rareza synatx que le permite verificar si una enumeración tiene un valor de los especificados?Manera rápida de verificar un rango de valores enum

Ejemplo:

enum fruit_and_vegetables 
{ 
    apples, 
    pears, 
    tomatoes, 
    cucumbers 
} 

int main() 
{ 
    fruit_and_vegetables something = apples; 
    if(something = {apples, pears}) // <-- this here 
     cout << "something is fruit." << endl; 
    else 
     cout "something is a vegetable." << endl; 
    return 0; 
} 

Gracias!

+2

tomates y pepinos * * son fruto ;-P –

+0

no según la Escoto: http://en.wikipedia.org/wiki/Tomato#Fruit_or_vegetable.3F –

+0

@Noah: '' tomates son * y no 'tomates es *' – ruslik

Respuesta

4

Ah, esto se puede hacer bastante fácil...

template <typename T> 
pair<T, fruit_and_vegetables> operator||(T t, fruit_and_vegetables v) { 
    return make_pair(t, v); 
} 

template <typename T> 
bool operator==(fruit_and vegetables lhs, pair<T, fruit_and_vegetables> rhs) { 
    return lhs == rhs.second || lhs == rhs.first; 
} 

Esto entonces se puede utilizar de esta manera:

if (something == (apple || pear || orange)) eat_the_yummy_fruit(something); 
else feed_to_rabbit(something) 

pero no funcionará si lo hace (apple || (pear || orange)). Esto se puede arreglar fácilmente pero quería mantener el código simple. Creo que esta es la única respuesta hasta el momento que realmente se escala para grandes enumeraciones ...

+0

¿Habría alguna manera de hacer funcionar grandes rangos también? Esto sería puramente por interés, ¡tu solución me permite hacer lo que quiero perfectamente! Gracias. – rubenvb

4

if (something < tomatoes)...

+1

Ah sí, '" ¿Por qué no pensé en eso? "(C)' ... pero ¿y si la enumeración tiene valores intermedios y mi ejemplo se vuelve más complicado/no ordenado? – rubenvb

5

No es que yo sepa, pero lo que puedes hacer es asignar valores 2^i a los miembros de enumeración. Por ejemplo:

enum fruit_and_vegetables 
{ 
    apples = (1<<0), 
    pears  = (1<<1), 
    tomatoes = (1<<2), 
    cucumbers = (1<<3) 
    // ... 
} 

A continuación, se puede comprobar con

if (something & (apples | pears | tomatoes)) 
    std::cout << "is tasty" << std::endl; 

Por supuesto, esto se limita a las enumeraciones con un tamaño razonable (creo que se puede tener un máximo de 32 elementos).

EDITAR

Si usted tiene más de 32 (64) los valores, hay que ser más creativo que esto. Al hacer varias comprobaciones, todavía puede ser razonablemente rápida:

enum fruit_and_vegetables { 
    apples = 1, //! 
    pears, 
    tomatoes, 
    cucumbers, 
    // ... 
    grapes 
} 
#define FRUIT_AND_VEGETABLES 120 

if ( (1<<something)  & ((1<<apples) | (1<<pears) | (1<<tomatoes)) 
    || (1<<(something-32) & ((1<<(apples-32)) | (1<<(pears-32)) | (1<<(tomatoes-32)))) 
    || ...) { 
    std::cout << "my keyboard is broken, but tastes good" << std::endl; 
} 

Pero eso no es realmente una gran solución. Si tiene una gran cantidad de enumeraciones y se pueden dividir en varias clases, entonces yo iría con Noah Roberts' answer.

+1

-1 por reclamar tomates son sabrosos! j/k Aunque diré que para cuando empieces a querer este tipo de comportamiento de tu enumeración, una enumeración no es realmente una construcción apropiada para el comportamiento que deseas. –

+2

¡Tienes que estar bromeando! ¡Los tomates son geniales! – bitmask

+2

@bitmask: ¿y si la enumeración contiene 70 miembros? ¡este acercamiento leftshift no funcionaría! – Nawaz

1

Hay otra manera, que se extiende la respuesta de @bitmask:

Supongamos que hay un número fijo de criterios que se puede comprobar. Así, en lugar de utilizar máscara de bits para los valores de fruit_and_vegetables enumeración (que se limite al tamaño de la palabra), puede utilizar LUT adicional:

enum fruit_and_vegetables { 
    apples = 0, 
    pears, 
    tomatoes, 
    cucumbers 
} 

enum qualifs { 
    is_fruit = 1, 
    is_sweet = 1<<1, 
    is_round = 1<<2, 
    is_tasty = 1<<3 
} 

const qualifs qualifs_LUT[] = { // can be generated 
    is_fruit | is_sweet | is_round, // apple 
    ... 
}; 

modo que comprobar que existe una voluntad de clasificación específica se convirtió

if (qualifs_LUT[tomato] & is_tasty) 

EDIT: y otro método interesante. Considere (nuevamente) el método @bitmask: Se basa en poderes de 2. Pero, ¿qué tal primos? Ellos crecen mucho más lentamente, por lo que mediante la asignación de números primos a los valores de enumeración, se puede squize más valores, asumiendo que el producto no se derrame:

enum fruit_and_vegetables { 
    apples = 2, 
    pears = 3, 
    tomatoes = 5, 
    cucumbers = 7 
} 

if ((apples * pears * tomatoes) % tomatoes == 0) 
    printf("it's tasty!"); 

éste es limitar el número de elementos del conjunto de control.

+0

¡Ámala! (Pero probablemente deberías hacer el lut 'const') – bitmask

+0

@bitmask: bueno, es solo un detalle de implementación :) – ruslik

+0

Lo sé, pero tuve que completar 15 caracteres :) – bitmask

1

Se puede escribir la plantilla de ayuda que le ayudará a lograr la sintaxis que desea:

enum fruit_and_vegetables 
{ 
    nothing, 
    apples, 
    pears, 
    tomatoes, 
    cucumbers 
}; 

// helper template 
typedef fruit_and_vegetables fav; 
template<fav v1 = nothing, fav v2 = nothing, fav v3 = nothing, fav v4 = nothing, 
    fav v5 = nothing, fav v6 = nothing, fav v7 = nothing, fav v8 = nothing> 
bool check_equal(fruit_and_vegetables value) 
{ 
    return (value == v1 || value == v2 || value == v3 || value == v4 || 
      value == v5 || value == v6 || value == v7 || value == v8); 
} 

// usage 
int main() 
{ 
    fruit_and_vegetables something = apples; 
    if(check_equal<apples, pears>(something)) 
     std::cout << "something is fruit." << std::endl; 
    else 
     std::cout << "something is a vegetable." << std::endl; 

    return 0; 
} 
+0

Es lo mismo que verificar cada valor a mano. OP pidió un método más rápido que el obvio. – ruslik

+1

OP preguntó acerca de la sintaxis simple: "oneline way of synatx weirdness". –

1

Para manejar grandes, conjuntos no ordenados de productos:

enum fruit_and_vegetables 
{ 
    apples, 
    pears, 
    tomatoes, 
    cucumbers, 
    MAX_VALUE 
}; 

vector<bool> arguablyVegetables(MAX_VALUE, false); 
arguablyVegetables[tomatoes] = true; 
arguablyVegetables[cucumbers] = true; 

cout << arguablyVegetables[apples] << endl; 
1

por qué no usar un set<fruit_and_vegetables> de lógica-o-ing varios fruit_and_vegetables? si se pone constexpr antes del operador operador || y == sobrecargas, así como ante los tipos de argumentos y de resultados, entonces el compilador evaluará su código en tiempo de compilación (sin sobrecarga de tiempo de ejecución) si es posible;) Escalas bien a mayores a || b || c || c rangos de enum y puede poner los valores entre paréntesis como lo desee.

#include <set> 
using std::set; 

enum fruit_and_vegetables 
{ 
    apples, 
    pears, 
    tomatoes, 
    cucumbers 
}; 

set<fruit_and_vegetables> operator||(fruit_and_vegetables left, fruit_and_vegetables right) { 
    set<fruit_and_vegetables> set; 
    set.insert(left); 
    set.insert(right); 
    return set; 
} 

set<fruit_and_vegetables> operator||(set<fruit_and_vegetables> left, fruit_and_vegetables right) { 
    left.insert(right); 
    return left; 
} 

set<fruit_and_vegetables> operator||(fruit_and_vegetables left, set<fruit_and_vegetables> right) { 
    right.insert(left); 
    return right; 
} 

bool operator!=(fruit_and_vegetables lhs, set<fruit_and_vegetables> rhs) { 
    return (rhs.find(lhs) == rhs.end()); 
} 

bool operator==(fruit_and_vegetables lhs, set<fruit_and_vegetables> rhs) { 
    return !(lhs != rhs); 
} 

int main() { 

fruit_and_vegetables fav = apples; 
if (fav == (apples || (pears || tomatoes))) cout << "match apples\n"; 
fav = cucumbers; 
if (fav == ((apples || pears) || tomatoes)) cout << "Error! matched ghost cucumbers\n"; 
if (fav != apples) cout << "correct no match apples\n"; 
if (fav == cucumbers) cout << "default operator==(FaV, FaV) match\n"; 
if (fav == (pears || apples)) cout << "yummi\n"; 

return 0; 
} 
Cuestiones relacionadas