Reputation: 12939
I can't find any resource online on how to use this method, which is quitely widely used in libraries.
What I'm referring to si something that looks like this:
someFun(Class::prop1 | Class::prop2 | Class::prop3, somethingelse);
now, I can undestand that this is based on enums/ints that are power of 2, so something like:
class Class{
public
enum{prop1 = 1, prop2 = 2, prop3 = 4, prop4 = 8};
};
and then use something like this to check if the n-th bit is 0 or 1, but are there ways to do it in a cleaner way?
If you wan you can use this as example:
class Class{
public:
enum{prop1 = 1, prop2 = 2, prop3 = 4};
void f(int i){
if( ... ) ...
}
};
I was thinking maybe using the &
operator, like if(i & Class::prop1) ...
but idk if it's the right way to do it
Upvotes: 1
Views: 590
Reputation: 3106
Your example is correct, and follows the classic C-style bitset using enums. As an alternative, you can declare the enum members using a left shift, which might improve readability for people unfamiliar:
enum Flags {
flag0 = 1<<0,
flag1 = 1<<1,
flag2 = 1<<2
};
The reason why flags & flag0
works in an if conditional is that the conditional only evaluates to false for an integral number if the number is 0. In a bitwise AND operation, where one of the operands is a power-of-2, this means that the particular bit is not set in the other operand.
An alternative is to declare your enum with implicit values:
enum class MyFlags {
flag0, flag1, flag2 // implicit values are consecutive, starting with 0
};
And then using std::bitset
either directly, or through a new type:
class MyBitset {
public:
explicit MyBitset(std::initializer_list<MyFlags> flags) {
for (MyFlags f : flags)
values.set(static_cast<unsigned>(f));
}
bool test(MyFlags f) { return values.test(static_cast<unsigned>(f); }
private:
std::bitset<WIDTH> values; // see below
};
The advantage is that now you can construct a set of flags with a initializer list, which a STL-like:
MyBitset({MyFlags::flag0, MyFlags::flag2})
The problem with this alternative is the maximum value. Ideally we would set the bitset width so that it has enough capacity for the most biggest flag value. We could have a type trait to specify that, and then MyBitset
could be generic:
template <class T> struct MyLimits;
template <> struct MyLimits<MyFlags> {
static constexpr bool isEnum = true;
static constexpr size_t min = static_cast<size_t>(Flags::flag0);
static constexpr size_t max = static_cast<size_t>(Flags::flag2);
};
// fails if MyLimits was not specialized for MyFlags
std::bitset<MyLimits<MyFlags>::max> values;
Upvotes: 1