Reputation: 3590
In C I am able to take two or more enumerated flags and inclusive OR them: (flag1 | flag2)
In C++ I cannot do the same thing. I have some flags that I've scoped to my class but to OR them I have to cast. It looks like this:
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;
}
That's kind of a mouthful, more in the real code than this example. I am wondering if there is a better way. I could change the argument passed to int void foo(int flags)
but then in the Visual Studio 2010 debugger I wouldn't see the flags ORed, just a number.
Without the cast I get an error:
obj.foo(name::test::firstflag | name::test::secondflag);
error C2664: 'name::test::foo' : cannot convert parameter 1 from 'int' to 'name::test::flag'
I searched on stackoverflow and found a question with the answer to overload the |
operator:
c++ - "enum - invalid conversion from int" in class - Stack Overflow
Yet when I use std::ios
flags I don't have to do any casting, why is that? For example fstream has a prototype like for example fstream(char *filename, std::ios_base)
and I can do this in my code:
fstream("filename", ios::in | ios::out);
What do you guys suggest? I do not have a lot of C++11 capabilities so if you could keep that in mind when answering. Thanks
Upvotes: 0
Views: 513
Reputation: 1
You can write a template class to convert flags to std::bitset<>
(which doesn't need c++11) indices and vice versa:
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;
};
Here's a sample for usage to convert the bitmask defined poll()
event types to index values for accessing the various flags represented with a std::bitset<>
in a convenient way:
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 ,
};
A corresponding std::bitset<>
can be manipulated using the indices defined in the enum above:
GetBitIndex<short>::BitsetType pollEventMask;
pollEvents[EV_POLLIN] = true; // set the POLLIN flag
pollEvents[EV_POLLERR] = false; // unset the POLLERR flag
The two operations above will do the same as:
short pollEventMask= POLLHUP | POLLERR; // Initialization just to show preset
// values
pollEventMask = (pollEventMask | POLLIN) & ~POLLERR; // This is the equivalent
// for the operations shown
// above
Some people claim for shortness, I personally claim for easy to read and use code on the semantics level (as long it doesn't hurt performance or footprint significantly).
A complete code sample can be found here (note it's only a gist I made, to bring it into productive state in another project).
Upvotes: 0
Reputation: 4387
std::bitset
is pretty good style for 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);
}
Upvotes: 1
Reputation: 66
In the GCC implementation of ios::in, ios::out, etc. They use operator overloading to get the desired effect. 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)); }
In your case you could define the following method:
inline flag operator|(flag f1, flag f2)
{
return flag(static_cast<int>(f1) | static_cast<int>(f2));
}
Cheers,
Upvotes: 5