【问题标题】:How to make functions with flag parameters? (C++)如何制作带有标志参数的函数? (C++)
【发布时间】:2009-10-19 15:07:49
【问题描述】:

如何创建一个带有标志的函数,例如 Windows 的 CreateWindow(...style | style,...),例如 createnum 函数:

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

这可能吗?如果可以,怎么做?

【问题讨论】:

    标签: c++ function flags


    【解决方案1】:

    您可以定义一个指定“一位”值的枚举(请注意,封闭结构在此处仅用作命名上下文,因此您可以编写例如MyFlags::EVEN):

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

    然后像这样使用它:

    int CreateNum(MyFlags::Value flags){
        if (flags & MyFlags::EVEN){
            // do something...
        }
    }
    
    void main(){
        CreateNum((MyFlags::Value)(MyFlags::EVEN | MyFlags::ODD));
    }
    

    或者只是这样:

    int CreateNum(int flags){
        if (flags & MyFlags::EVEN){
            // do something...
        }
    }
    
    void main(){
        CreateNum(MyFlags::EVEN | MyFlags::ODD);
    }
    

    您也可以简单地声明整数常量,但我认为枚举更清晰。

    注意:我更新了帖子以考虑到一些 cmets,谢谢!

    【讨论】:

    • 也许你可以让你的枚举更长,以明确它必须是 2 的幂?
    • +1。顺便说一句,没有必要将标志与“== MyFlags::EVEN”进行比较,因为它将为零或非零,这会自动强制转换为相当不错的布尔值。
    • danadam 是对的:参数不应该是 'MyFlags::Value',因为标志的组合不是 MyFlags::Value(例如 EVEN | ODD 给出 3,这不是有效的枚举成员)。你仍然可以施放组合,但它很脏。
    • 小提示:我发现将枚举值写成这样更好:1
    • @Marcus:在我看来,这两种记法出错的可能性是一样的,你不觉得吗:)?
    【解决方案2】:

    我赞成 orsogufo 的回答,但我一直喜欢通过以下方式定义值:

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

    我也喜欢在适当的时候组合一些常见的标志组合。

    【讨论】:

    • 很好的解决方案。逻辑移位的引入使阅读更新更容易。
    【解决方案3】:

    你可以像这样使用const int

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

    当你使用它时:

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

    当然,您可以使用| 运算符在您的标志中添加一个或多个标志。

    【讨论】:

    • #define FLAG1 0x0001 更改为const int FLAG1=0x0001;
    • 同意 Alexey... 不要为此使用宏。
    • const int 现在可以替换为constexpr int
    【解决方案4】:

    使用 2 的幂作为单个常数,例如

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

    你使用逻辑和运算符'&'进行测试,比如

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

    【讨论】:

      【解决方案5】:

      你的测试出错了。你想要的是类似(flags &amp; EVEN) 的东西,其中 EVEN 是一个具有单个位集的整数(1、2、4、8、16 - 2 的某个幂)。 (整数可以是 int 或 enum。你可以有一个宏,但这通常不是一个好主意。)

      您可以通过重载flags::operator==(flagvalue f) 来使用您列出的符号,但这是个坏主意。

      【讨论】:

        【解决方案6】:
        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
        }
        

        还说明了位字段的屏蔽,当您只需要在不添加任何额外数据结构的情况下添加一个简单的额外功能时,这可能很有用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-11
          • 2012-03-21
          • 1970-01-01
          • 2011-10-27
          • 2021-09-28
          • 2021-11-23
          • 2015-11-08
          • 1970-01-01
          相关资源
          最近更新 更多