C++ 在C+中键入定义位字段/掩码+;

C++ 在C+中键入定义位字段/掩码+;,c++,enums,typedef,bit-fields,C++,Enums,Typedef,Bit Fields,我在C++中遇到了这个问题:我可以键入一个值来自枚举的位字段吗 代码将更具解释性: typedef { AUDIO = 0x01, VIDEO = 0x02, SUBTITLE = 0x04, DATA = 0x08, GUARD, ALL = 0xFF } my_enum_e; // I'd like to replace 'unsigned int' by 'my_enum_e' or similar int myFunction( unsigne

我在C++中遇到了这个问题:我可以键入一个值来自枚举的位字段吗

代码将更具解释性:

typedef {
 AUDIO    = 0x01,
 VIDEO    = 0x02,
 SUBTITLE = 0x04,
 DATA     = 0x08,
 GUARD,
 ALL      = 0xFF
} my_enum_e;

// I'd like to replace 'unsigned int' by 'my_enum_e' or similar
int myFunction( unsigned int mask ) 
{
  // code
}

// called like this:
myFunction( AUDIO|VIDEO|DATA );
在函数的原型中,我想使用
my_enum_e
作为输入值类型,这样在探索代码时,您就可以立即知道应该在其中输入哪些值

现在,将原型更改为

int myFunction( my_enum_e mask );
使编译器抱怨强制转换错误。我无法通过如下方式转换函数调用来修复它:

int myFunction( my_enum_e mask )
{
    // code
}

myFunction( (my_enum_e)(VIDEO|AUDIO|DATA) );
但我觉得这很可怕,我甚至不确定它是否合法(它会截断值吗??。

你有解决办法吗< P>来分析它:如何实现一个特殊的函数来处理这个问题:

template <typename Enum>
Enum bitField(unsigned bits) {
  return static_cast<Enum>(bits);
}
模板
枚举位字段(无符号位){
返回静态_-cast(位);
}
它为您的工作增添了表现力:

myFunction(bitField<my_enum_e>(VIDEO|AUDIO|DATA));
myFunction(位域(视频|音频|数据));
如果您想要更复杂,您可以这样做:

template <typename Enum>
struct BitField {
  Enum value;
  BitField(Enum value) : value(value) {}
  BitField operator|(Enum more) {
    return BitField(value | more);
  }
  BitField operator&(Enum more) {
    return BitField(value & more);
  }
  BitField operator~() {
    return BitField(~value);
  }
  operator Enum() {
    return value;
  }
}
模板
结构位域{
枚举值;
位字段(枚举值):值(值){}
位域运算符|(枚举更多){
返回位字段(值|更多);
}
位域运算符&(枚举更多){
返回位字段(值及更多);
}
位域运算符(){
返回位字段(~value);
}
运算符Enum(){
返回值;
}
}
这样你就可以写作了

myFunction(BitField<my_enum_e>(VIDEO) | AUDIO | DATA);
myFunction(位域(视频)|音频|数据);

一种解决方法是
typedefint MY_标志然后#定义所有值:
#定义音频0x01
等。这样编译器就不会抱怨了,您的函数调用中仍然会得到类型:

int myFunction( MY_FLAGS mask );

myFunction( VIDEO|AUDIO|DATA );

|
和其他运算符添加显式重载

my_enum_e operator|(my_enum_e a, my_enum_e b) 
    { return my_enum_e(unsigned(a)|unsigned(b)); }
可以编写一个宏来定义给定位掩码类型所需的所有运算符

#define BITMASK_OPERATORS(T)   T operator|(T a, T b) { return T(unsigned(a)|unsigned(b)); } \
                                 T operator^(T a, T b) ...

我建议您查看以下线程:-在[Boost Vault](filename
enum_rev4.6.zip
)中提到的实现。还可以声明一个
BOOST\u位字段

BOOST_BITFIELD(my_enum_e, 
  (AUDIO)    (0x01)
  (VIDEO)    (0x02)
  (SUBTITLE) (0x04)
  (DATA)     (0x08)
);
然后,您可以声明您的函数:

int myFunction( const my_enum_e & in_enum ) 
{
  if ( in_enum[AUDIO] ) ...
}
用法是

void callerFunction()
{
  my_enum_e mask;
  mask.set(my_enum_e::AUDIO);
  mask.set(my_enum_e::VIDEO | my_enum_e::SUBTITLE );
  cout << mask << " = " << hex << mask.value() << endl; // will print: AUDIO|VIDEO|SUBTITLE = 0x7
  myFunction( mask );

}
void callerFunction()
{
我的数字面具;
mask.set(my_enum_e::AUDIO);
mask.set(my_enum_e::VIDEO | my_enum_e::SUBTITLE);

在代码< > TyPulf< /Cord>故意之后,你是否省略了<代码> EnUM <代码>关键字?有,是的,我不知道它是否危险。我的所有类型都使用“未命名的”结构/EnUM。相关的用户名的UpDebug。@ Gui13,在C++中,你最好是<代码> EnUM E{};< /> > > <代码> TyPulfEnUM {}E;
不管怎样。是我的旧C行李又来敲门了吗?:)我刚刚意识到,如果你的函数采用枚举,并且你要组合值,那么每次组合都需要在该枚举中包含一些内容,否则就是UB。@chris:嗯,是的,当然。我怎么会错过它呢?!让我来修复它。尽管你的解决方案很优雅,但我还是会采用n.m.的解决方案在C++的头文件中定义< <代码> >是邪恶的。永远不要这样做,它会使范围混乱,而且会适得其反。为什么?它是一个干净清晰的解决方案,不像有些……哦,你的!太好了!只是一个小提示:你必须把代码< < < />代码>和<代码> B/C> >其他东西(如<代码>未签名< /代码>)为了避免无休止的递归。哦,是的。对不起。我确实进行了强制转换,但在尝试缩短代码时删除了它,并且没有检查它:(