开发者

How to make functions with flag parameters? (C++)

开发者 https://www.devze.com 2022-12-09 01:17 出处:网络
How could I make a function with flags like how Windows\' CreateWindow(...style | style,...), for example, a createnum function:

How could I make a function with flags like how Windows' CreateWindow(...style | style,...), for example, a createnum function:

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);

Is this possible, and if 开发者_C百科so, how?


You can define an enum specifying "single bit" values (note that the enclosing struct is acting here only as a naming context, so that you can write e.g. MyFlags::EVEN):

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

and then use it like this:

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

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

or simply like this:

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

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

You could also simply declare integer constants, but the enum is clearer in my opinion.

Note: I updated the post to take some comments into account, thanks!


I upvoted orsogufo's answer, but I always liked doing the following for defining the values:

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
};

<< is the shift operator. Incrementing the right side lets you generate sequential bit masks by moving the 1 over, one bit at a time. This has the same values for the bare flags, but reads easier to my eyes and makes it obvious if you skip or duplicate a value.

I also like combining some common flag combinations when appropriate.


You can use const int like this:

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

And when you use it:

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

    if( flags & FLAG2 )
        // FLAG2 is present

    // ...
}

Of course you can put one or more flag in your flags using the | operator.


Use powers of two as the individual constants, like

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

and you use the logical and operator '&' for testing, like

if( flags & GREATER_THAN_TEN)
    num = 11;
if( (flags & EVEN) && (num % 2) == 1 )
    num++;
else if ( (flags & ODD) && (num % 2) == 0 )
    num++;
return num;


You've got your tests wrong. What you want is something like (flags & EVEN), where EVEN is an integer with a single bit set (1, 2, 4, 8, 16 - some power of 2). (The integer can be an int or an enum. You could have a macro, but that's generally not a good idea.)

You can use the notation you listed, by overloading flags::operator==(flagvalue f), but it's a bad idea.


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
}

Illustrates masking of bit fields too which can be useful when you just need to bolt on a simplistic bit of extra functionality without adding any extra data structure.

0

精彩评论

暂无评论...
验证码 换一张
取 消