在C中,我可以使用两个或多个枚举标记并包含OR:(flag1 | flag2)
在C ++中我不能做同样的事情。我有一些旗帜,我已经限制在我的班级,但对于他们我必须施展。它看起来像这样:
namespace name
{
class test
{
public:
enum flag
{
firstflag = 1, secondflag = 2, thirdflag = 4
};
void foo(flag flags)
{
return;
}
};
}
int main(int argc, char *argv[])
{
name::test obj;
obj.foo((name::test::flag)(name::test::firstflag | name::test::secondflag));
return 0;
}
这是一个满口的,比实例更真实的代码。我想知道是否有更好的方法。我可以更改传递给int void foo(int flags)
的参数,但随后在Visual Studio 2010调试器中,我看不到标记ORed,只是一个数字。
没有演员,我得到一个错误:
obj.foo(name::test::firstflag | name::test::secondflag);
error C2664: 'name::test::foo' : cannot convert parameter 1 from 'int' to 'name::test::flag'
我在stackoverflow上搜索并找到一个问题,答案是重载|
运算符:
c++ - "enum - invalid conversion from int" in class - Stack Overflow
然而,当我使用std::ios
标志时,我不需要进行任何演员,为什么呢?例如,fstream有一个原型,例如fstream(char *filename, std::ios_base)
,我可以在我的代码中执行此操作:
fstream("filename", ios::in | ios::out);
你们有什么建议?我没有很多C ++ 11功能,所以如果你能在回答时记住这一点。感谢
答案 0 :(得分:4)
在ios :: in,ios :: out等的GCC实现中,它们使用运算符重载来获得所需的效果。 E.g。
inline _GLIBCXX_CONSTEXPR _Ios_Openmode
operator|(_Ios_Openmode __a, _Ios_Openmode __b)
{ return _Ios_Openmode(static_cast<int>(__a) | static_cast<int>(__b)); }
在您的情况下,您可以定义以下方法:
inline flag operator|(flag f1, flag f2)
{
return flag(static_cast<int>(f1) | static_cast<int>(f2));
}
干杯,
答案 1 :(得分:1)
std::bitset
对于C ++来说是非常好的风格。 Reference
#include <bitset>
namespace Flags {
enum Flags {
first, second, third, NUM_FLAGS
};
}
class Test {
public:
void foo(std::bitset<Flags::NUM_FLAGS> flags) {
return;
}
};
int main() {
std::bitset<Flags::NUM_FLAGS> flags;
flags[Flags::first] = true;
flags[Flags::second] = false;
flags[Flags::third] = true;
Test obj;
obj.foo(flags);
}
答案 2 :(得分:0)
您可以编写模板类,将标志转换为std::bitset<>
(不需要c++11)索引,反之亦然:
template<typename BitFieldType, BitFieldType BitValue, int8_t CurIndex>
struct BitIndexSelector;
template<typename BitFieldType, BitFieldType BitValue, int8_t CurIndex>
struct BitIndexSelector
{
static const int8_t ResultIndex =
((CurIndex != -1) &&
(((((BitFieldType)1) << CurIndex) & BitValue) > 0)
? CurIndex
: BitIndexSelector
<BitFieldType
,BitValue
,CurIndex - 1>::ResultIndex);
};
template<typename BitFieldType, BitFieldType BitValue>
struct BitIndexSelector<BitFieldType,BitValue,-1>
{
static const int8_t ResultIndex = -1;
};
template<typename BitFieldType, BitFieldType BitValue = 0>
struct GetBitIndex
{
static const int8_t Index =
BitIndexSelector
< BitFieldType
, BitValue
, sizeof(BitFieldType) * sizeof(char) * CHAR_BIT>::ResultIndex;
typedef std::bitset<sizeof(BitFieldType) * CHAR_BIT> BitsetType;
};
这是一个用于将位掩码定义的poll()
事件类型转换为索引值的示例,用于以方便的方式访问用std::bitset<>
表示的各种标志:
enum PollEvents
{
EV_POLLIN = GetBitIndex<short,POLLIN>::Index ,
EV_POLLOUT = GetBitIndex<short,POLLOUT>::Index ,
EV_POLLPRI = GetBitIndex<short,POLLPRI>::Index ,
EV_POLLRDHUP = GetBitIndex<short,POLLRDHUP>::Index ,
EV_POLLERR = GetBitIndex<short,POLLERR>::Index ,
EV_POLLHUP = GetBitIndex<short,POLLHUP>::Index ,
};
可以使用上面枚举中定义的索引来操作相应的std::bitset<>
:
GetBitIndex<short>::BitsetType pollEventMask;
pollEvents[EV_POLLIN] = true; // set the POLLIN flag
pollEvents[EV_POLLERR] = false; // unset the POLLERR flag
上面的两个操作将执行相同的操作:
short pollEventMask= POLLHUP | POLLERR; // Initialization just to show preset
// values
pollEventMask = (pollEventMask | POLLIN) & ~POLLERR; // This is the equivalent
// for the operations shown
// above
有些人声称自己很简短,我个人声称在语义层面上易于阅读和使用代码(只要它不会显着损害性能或占用空间)。
可以找到一个完整的代码示例here(请注意,这只是我做的一个要点,在另一个项目中将其带入生产状态)。