C++ C++;使用位移位指定枚举显式值
我一直在研究开源项目中的一些代码,并注意到不止一次枚举的值是通过将一个值进行位移位来分配的,并且是递增的。我看不出这样做的任何具体原因,也看不到通过增加+1来分配值的效率有什么提高 不管怎样,如果没有一些代码来证明什么让我感到困惑,这可能没有什么意义 一级C++ C++;使用位移位指定枚举显式值,c++,enums,openscenegraph,C++,Enums,Openscenegraph,我一直在研究开源项目中的一些代码,并注意到不止一次枚举的值是通过将一个值进行位移位来分配的,并且是递增的。我看不出这样做的任何具体原因,也看不到通过增加+1来分配值的效率有什么提高 不管怎样,如果没有一些代码来证明什么让我感到困惑,这可能没有什么意义 一级 enum EventType { NONE = 0, PUSH = 1<<0, RELEASE =
enum EventType {
NONE = 0,
PUSH = 1<<0,
RELEASE = 1<<1,
DOUBLECLICK = 1<<2,
DRAG = 1<<3,
MOVE = 1<<4,
KEYDOWN = 1<<5,
KEYUP = 1<<6,
FRAME = 1<<7,
RESIZE = 1<<8,
SCROLL = 1<<9,
PEN_PRESSURE = 1<<10,
PEN_ORIENTATION = 1<<11,
PEN_PROXIMITY_ENTER = 1<<12,
PEN_PROXIMITY_LEAVE = 1<<13,
CLOSE_WINDOW = 1<<14,
QUIT_APPLICATION = 1<<15,
USER = 1<<16
};
之所以要这样做,是因为可以使用以这种方式定义为位掩码的枚举。给定一个32位整数,您可以有32个唯一的特征,这些特征都可以使用枚举值的逐位组合来启用或禁用 例如,如果您想创建一个事件处理程序,在使用位移位的实现中侦听
QUIT_应用程序
和CLOSE_窗口
,只需使用QUIT_应用程序| CLOSE_窗口
。每个枚举都是一个位,将它们组合在一起可以方便地指定所需的每种类型的事件,如果只是从1-16枚举它们,则无法这样做
考虑这样一种情况,您需要一个事件处理程序,它使用您建议的“更高效”枚举侦听PUSH
和RELEASE
。如果你把它们放在一起,你会得到3
3
也是示例中双击的值。所以没有办法知道你真正想要的是什么活动;它是由PUSH
和RELEASE
组合而成,还是仅仅是双击
?这就是为什么为每个枚举类型保留一个位是如此强大的原因
您经常会看到这样定义的枚举值:
enum EventType {
NONE = 0,
PUSH = 1,
RELEASE = 2,
DOUBLECLICK = 3,
DRAG = 4,
MOVE = 5,
KEYDOWN = 6,
KEYUP = 7,
FRAME = 8,
RESIZE = 9,
SCROLL = 10,
PEN_PRESSURE = 11,
PEN_ORIENTATION = 12,
PEN_PROXIMITY_ENTER = 13,
PEN_PROXIMITY_LEAVE = 14,
CLOSE_WINDOW = 15,
QUIT_APPLICATION = 16,
USER = 17
};
enum EventType {
NONE = 0,
PUSH = 0x1,
RELEASE = 0x2,
DOUBLECLICK = 0x4,
DRAG = 0x8,
MOVE = 0x10,
KEYDOWN = 0x20,
KEYUP = 0x40,
FRAME = 0x80,
RESIZE = 0x100,
SCROLL = 0x200,
PEN_PRESSURE = 0x400,
PEN_ORIENTATION = 0x800,
PEN_PROXIMITY_ENTER = 0x1000,
PEN_PROXIMITY_LEAVE = 0x2000,
CLOSE_WINDOW = 0x4000,
QUIT_APPLICATION = 0x8000,
USER = 0x10000
};
有时你甚至会看到这样的事情:
...
CLOSE_WINDOW = 0x4000,
QUIT_APPLICATION = 0x8000,
CLOSE_AND_QUIT = CLOSE_WINDOW | QUIT_APPLICATION,
...
位移位表示法更容易阅读(对于某些人来说),它们都做相同的事情。每个枚举值表示一个位或位的离散组合(除了表示没有所有位的
NONE
。这样做的通常原因是将每个枚举值与最终v值的一个位相关联,因此您可以(例如)将多个标志编码到单个变量中
例如,对于典型的32位系统,您可以将32个单独的标志编码(显然已经足够了)为单个32位int
(或者,最好是unsigned int
)
例如,如果您正在查看键盘上的键,则可以将字母和数字等“普通”键编码为一个字节(如您所建议的,可能使用连续值),将shift、alt和control等“修改器”键编码为单个位。这将允许您(例如)将control+alt+A之类的内容编码为单个值
同样,对于鼠标消息,您可以将鼠标按钮视为“修改器”,因此可以将拖动鼠标之类的内容编码为单个值
在这两种情况下,将“修饰符”编码为单个位的重要一点是,这允许您以后毫不含糊地检索这些修饰符——如果在值中设置了正确的位,则使用该修饰符。相比之下,如果你只使用连续的数字,你就不能在之后提取单个片段。例如,如果将输入编码为
1
、2
和3
,则无法判断3
是用于指示与3
相对应的原始输入,还是同时指示1
和2
的输入。但是,如果你将这些值编码为<代码> 1 < /C>,<代码> 2 和<代码> 4 >代码>,你可以组合值,并且仍然解码它们,这样你就可以准确地看到输入需要什么来产生特定的值。 < P>这是因为一个东西可以用C++实现的情况之一。没有添加显式实现它的机制
枚举提供链接器/调试器可见常量,并且可以限定为类和模板的范围,因此,尽管它不能完全实现最终用户试图实现的目标,当然也不能显式实现,枚举表达式中的值不必是连续的,这意味着它被认为足以实现枚举位掩码
结果值可直接用于位掩码,例如:
enum {
Widget = 1 << 0, // value b00000001
Dingo = 1 << 1, // value b00000010
Herp = 1 << 2 // value b00000100
};
if (flag & Widget)
doWidgetThings();
if (flag & Dingo)
feedTheDog(baby);
if (flag & Herp)
win();
这是一个好主意。您可以通过按位or(
|
)组合多个枚举数,并将结果存储在类型为EventType
的单个对象中。答案很好,非常有意义。我想我从来没有考虑过多个事件同时发生,但支持这样的事情是有道理的。
enum {
Widget = 1 << 0, // value b00000001
Dingo = 1 << 1, // value b00000010
Herp = 1 << 2 // value b00000100
};
if (flag & Widget)
doWidgetThings();
if (flag & Dingo)
feedTheDog(baby);
if (flag & Herp)
win();
flag = 0; // matches none
flag = Herp; // matches one flag.
flag = Widget | Dingo; // sets flag to have both widget and dingo.