2009-10-19 7 views
9

¿Cómo podría hacer una función con banderas como la forma CreateWindow de Windows' (... estilo | estilo, ...), por ejemplo, una función createnum:¿Cómo hacer funciones con parámetros de indicador? (C++)

int CreateNum(flag flags) //??? 
{ 
    int num = 0; 
    if(flags == GREATER_THAN_TEN) 
     num = 11; 
    if(flags == EVEN && ((num % 2) == 1) 
     num++; 
    else if(flags == ODD && ((num % 2) == 0) 
     num++; 
    return num; 
} 
//called like this 
int Number = CreateNum(GREATER_THAN_TEN | EVEN); 

Es esto posible, y ¿si es así, cómo?

Respuesta

27

Se puede definir una enumeración que especifica los valores "de un solo bit" (tenga en cuenta que la estructura de cerramiento está actuando aquí sólo como un contexto de nombres, por lo que se puede escribir por ejemplo MyFlags::EVEN):

struct MyFlags{ 
    enum Value{ 
     EVEN       = 0x01, 
     ODD       = 0x02, 
     ANOTHER_FLAG     = 0x04, 
     YET_ANOTHER_FLAG    = 0x08, 
     SOMETHING_ELSE     = 0x10, 
     SOMETHING_COMPLETELY_DIFFERENT = 0x20 
    }; 
}; 

y luego usarlo de esta manera:

int CreateNum(MyFlags::Value flags){ 
    if (flags & MyFlags::EVEN){ 
     // do something... 
    } 
} 

void main(){ 
    CreateNum((MyFlags::Value)(MyFlags::EVEN | MyFlags::ODD)); 
} 

o simplemente como esto:

int CreateNum(int flags){ 
    if (flags & MyFlags::EVEN){ 
     // do something... 
    } 
} 

void main(){ 
    CreateNum(MyFlags::EVEN | MyFlags::ODD); 
} 

Usted también podría simplemente declarar constantes enteras, pero la enumeración es más clara en mi opinión.

Nota: He actualizado la publicación para tomar algunos comentarios en cuenta, ¡gracias!

+5

¿Tal vez podría hacer que su enumeración sea más larga, para aclarar que TIENE que ser potencias de dos? – KeatsPeeks

+1

+1. como un lado, no es necesario comparar la bandera con "== MyFlags :: EVEN", ya que será cero o distinto de cero, lo que automáticamente coacciona a bool bastante bien. – rmeador

+0

No creo que sea posible pasar dos (o más) banderas usando | operador si usa este enfoque. – danadam

5

Puede utilizar const int así:

const int FLAG1 = 0x0001; 
const int FLAG2 = 0x0010; 
const int FLAG3 = 0x0100; 
// ... 

Y cuando utilizarlo:

int CreateNum(int flags) 
{ 
    if(flags & FLAG1) 
     // FLAG1 is present 

    if(flags & FLAG2) 
     // FLAG2 is present 

    // ... 
} 

Por supuesto se puede poner uno o más de sus banderas bandera usando el operador |.

+4

Cambie '#define FLAG1 0x0001' a' const int FLAG1 = 0x0001; ' –

+0

de acuerdo con Alexey ... no use macros para esto. – Bill

+0

Sí, tienes razón, es mejor. Lo he cambiado –

0

Tiene las pruebas equivocadas. Lo que quiere es algo como (flags & EVEN), donde EVEN es un número entero con un único bit configurado (1, 2, 4, 8, 16 - alguna potencia de 2). (El número entero puede ser un int o una enumeración. Podría tener una macro, pero generalmente no es una buena idea.)

Puede usar la notación que enumeró, al sobrecargar flags::operator==(flagvalue f), pero es una mala idea.

1

Use potencias de dos, como las constantes individuales, como

enum Flags { EVEN = 0x1, ODD = 0x2, GREATER_TEN = 0x4 }; 

y utiliza la lógica y el operador '&' para las pruebas, como

if(flags & GREATER_THAN_TEN) 
    num = 11; 
if((flags & EVEN) && (num % 2) == 1) 
    num++; 
else if ((flags & ODD) && (num % 2) == 0) 
    num++; 
return num; 
0
enum flags { 
    EVEN =  0x0100, 
    ODD =   0x0200, 
    BELOW_TEN = 0x0400, 
    ABOVETEN = 0x0800, 
    HUNDRED =  0x1000, 
    MASK =  0xff00 
}; 

void some_func(int id_and_flags) 
{ 
    int the_id = id_and_flags & ~MASK; 
    int flags = id_and_flags & MASK; 
    if ((flags & EVEN) && (the_id % 2) == 1) 
     ++the_id; 
    if ((flags & ODD) && (the_id % 2) == 0) 
     ++the_id; 
    // etc 
} 

Ilustra el enmascaramiento de los campos de bits también, que puede ser útil cuando solo necesitas usar un poco de funcionalidad adicional sin agregar ninguna estructura de datos adicional.

10

I upvoted respuesta de orsogufo, pero siempre me gusta hacer lo siguiente para definir los valores:

enum Value{ 
    EVEN       = (1<<0), 
    ODD       = (1<<2),   
    ANOTHER_FLAG     = (1<<3),   
    YET_ANOTHER_FLAG    = (1<<4),   
    SOMETHING_ELSE     = (1<<5),   
    SOMETHING_COMPLETELY_DIFFERENT = (1<<6), 

    ANOTHER_EVEN     = EVEN|ANOTHER_FLAG 
}; 

< < es el operador de desplazamiento. Incrementar el lado derecho le permite generar máscaras de bits secuenciales moviendo el 1, un bit a la vez. Esto tiene los mismos valores para las banderas desnudas, pero me resulta más fácil de leer y lo hace obvio si omite o duplica un valor.

También me gusta combinar algunas combinaciones de banderas comunes cuando sea apropiado.

+0

+1 de mí; Yo también, como definir "combinaciones comunes" :) –

Cuestiones relacionadas