2012-04-26 23 views
11

I tienen una API C que define una enumeración de este modo:Uso de enumeraciones bandera C en C++

typedef enum 
{ 
    C_ENUM_VALUE_NONE = 0, 
    C_ENUM_VALUE_APPLE = (1 << 0), 
    C_ENUM_VALUE_BANANA = (1 << 1), 
    C_ENUM_VALUE_COCONUT = (1 << 2), 
    // etc. 
    C_ENUM_VALUE_ANY  = ~0 
} CEnumType; 

hay un método que utiliza la enumeración, se define como:

void do_something(CEnumType types); 

En C, puede llamar algo así como:

do_something(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA); 

Sin embargo, si se intenta llamar de esta manera en C++ (Linux, compilador g ++), se produce un error, conversión no válida de 'int' a 'CEnumType'.

¿Cuál es la forma correcta de utilizar esta API C desde mi aplicación C++?

Respuesta

22

Es necesario echar int s a enumeraciones en C++, pero puede ocultar el molde en una operadora personalizada OR:

CEnumType operator|(CEnumType lhs, CEnumType rhs) { 
    return (CEnumType) ((int)lhs| (int)rhs); 
} 

Con este operador en su lugar, usted puede escribir su original

do_something(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA); 

y se compilará y se ejecutará sin problemas.

+3

+1 por la astucia de sobrecargar el operador' | '! –

+2

¿Es un comportamiento bien definido tener un objeto de tipo enum cuyo valor no es uno de los valores enum especificados? – bames53

+0

Estoy bastante seguro de que esta conversión (int) completa es redundante porque tu enumeración ya tiene algún tipo de almacenamiento o puede especificarse con enum X: int {} – Andy

0

Al ordenar dos valores enum, está creando un valor no válido (0x3 no está en la enumeración CEnumType). Las enumeraciones no son bitfields. Si quieres un campo de bits, define uno.

Puede convertir el valor si desea forzarlo, pero eso puede sorprender a algunos códigos que cuentan con solo poder obtener los valores enumerados.

do_something((CEnumType)(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA)); 
+1

No definió esta interfaz, está utilizando una interfaz definida por otra persona diseñada para C. Supuestamente no puede (y no debería) cambiar el código de la biblioteca. – dsharlet

+0

Enum está ahí para simplificar la declaración, y la función está aceptando enum solo para dar pistas al desarrollador de C donde buscar valores que puedan definirse para formar una entrada ... Nada de malo en eso, solo una manera diferente de pensar. Más como C y no C++. –

+1

"* Al ordenar dos valores enum, está creando un valor no válido (0x3 no está en enumerando CEnumType) *" Creo que esto está mal. Es solo porque el operador bit a bit evalúa int y, por lo tanto, el error. No porque se evaluó a 0x3, que no está en la enumeración –

6

C++ tiene reglas más estrictas que C con respecto a enums. Tendrá que convertir el valor al tipo de enumeración al llamar:

do_something((CEnumType)(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA)); 

Alternativamente, puede escritor de una función de contenedor que toma un int para hacer el molde para usted, si se quiere evitar escribir el yeso todos vez que la llame:

void do_something_wrapper(int types) 
{ 
    do_something((CEnumType)types); 
} 
... 
do_something_wrapper(C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA); 

Aunque no sé si quiero ver lo que se obtiene cuando se cruza una manzana con un plátano ...

5

En el caso de operaciones bit a bit, la expresión evalúa a un tipo primitivo, es decir, int, long, etc. Sin embargo, su función toma un tipo no primitivo (CEnumType). La única forma que conozco de eludir esto es emitir la expresión. Por ejemplo:

do_something((CEnumType) (C_ENUM_VALUE_APPLE | C_ENUM_VALUE_BANANA)); 
+0

+1 para señalar la evaluación de la expresión a 'int'. do_something (C_ENUM_VALUE_APPLE) funcionaría bien sin ningún molde. Es porque la expresión evaluada como 'int' que se requiere un molde –

1

CEnumType A;

A = (CEnumType) (A | C_ENUM_VALUE_APPLE);

Puede usarlo también.

Cuestiones relacionadas