在开关情况下使用按位或运算符

问题描述

我有一个枚举

enum ENUM_MSG_TEXT_CHANGE {COLOR=0,SIZE,UNDERLINE};

    void Func(int nChange)
    {
bool bColor=false,bSize=false;
    switch(nChange)
    {
    case COLOR:bColor=true;break;
    case SIZE:bSize=true;break;
    case COLOR|SIZE:bSize=true; bColor=true;break;
    }
    }

case SIZE:和case COLOR | SIZE:都给出值1,所以我得到了错误C2196:case value'1'已经被使用。如何在切换案例中区分这两种情况?

谢谢

解决方法

如果要创建位掩码,枚举的每个元素都必须对应于2的幂的数字,因此它恰好设置了1位。如果您不给它们编号,它将无法正常工作。因此,第一个元素应该是1,然后是2,然后是4,然后是8,然后是16,依此类推,因此在排列它们时不会出现重叠。另外,您应该单独测试每一位,而不是使用开关:

if (nChange & COLOR) {
    bColor = true;
}
if (nChange & SIZE) {
    bSize = true;
}
,

这两个标签

case SIZE:bSize=true;break;
case COLOR|SIZE:bSize=true; bColor=true;break;

求值为1,因为SIZE被定义为具有值1,并且标签|中使用的按位运算符COLOR|SIZE也会产生1。

通常,此类枚举被声明为位掩码类型,例如

enum ENUM_MSG_TEXT_CHANGE { COLOR = 1 << 0,SIZE = 1 << 1,UNDERLINE = 1 << 2 };

在这种情况下,此标签

case COLOR|SIZE:bSize=true; bColor=true;break;

等于3。

,

使用二进制ORoperator|)时,需要将值分配给各个位(或位的组合)。由于COLOR的值为0,因此无法像您尝试的那样从位域中提取它。

此外,对于您拥有的三个enum,有8种可能的组合。要使用switch,您需要8个case标签。

将此作为替代方法:

#include <iostream>

enum ENUM_MSG_TEXT_CHANGE : unsigned {
    COLOR     = 1U << 0U,// 0b001
    SIZE      = 1U << 1U,// 0b010
    UNDERLINE = 1U << 2U  // 0b100
};

void Func(unsigned nChange) {
    // extract the set bits
    bool bColor     = nChange & COLOR;
    bool bSize      = nChange & SIZE;
    bool bUnderline = nChange & UNDERLINE;

    // print out what was extracted
    std::cout << bUnderline << bSize << bColor << '\n';
}

int main() {
    // test all combinations
    for(unsigned change = 0; change <= (COLOR | SIZE | UNDERLINE); ++change) {
        Func(change);
    }
}

输出:

000
001
010
011
100
101
110
111