Reputation: 1299
In order to define an enum to be used as bit flags, one would define the enum itself, with appropriate values, and define bitwise operators for the enum type, as below.
enum ENUM_TYPE
{
ET_VAL1 = 1L << 0,
ET_VAL2 = 1L << 1
}
inline ENUM_TYPE operator& (ENUM_TYPE _a, ENUM_TYPE _b)
{return ENUM_TYPE(static_cast<int>(_a) & static_cast<int>(_b));}
/* similarly for |, ^, ~, |=, &=, ^= */
The problem is that the definition of the bitwise operators takes a lot of space, makes code difficult to read, and is annoying to write, specially if various enums are defined.
One could create a template, as below, in a header file, and simply include that whenever necessary. This introduces the risk of using the bitwise operators on types for which one did not explicitly define them, however.
template<typename ENUM_T>
inline ENUM_T operator& (ENUM_T _a, ENUM_T _b)
{return ENUM_T(static_cast<int>(_a) & static_cast<int>(_b));}
One could also create macros, as below. This seems error prone though?
#define BITWISE_AND(TYPE) inline TYPE operator& (TYPE _a, TYPE _b)\
{return TYPE(static_cast<int>(_a) & static_cast<int>(_b));}
#define BITWISE_ALL(TYPE) BITWISE_AND(TYPE) /* and others */
What is the "correct" way to do the above? Are various flag definitions a code smell? What is normally done in production code?
Upvotes: 2
Views: 2939
Reputation: 60474
If you are going to redefine the operators anyway, why not use meaningful ones? The bitwise or operator makes no sense when you really want to say "ET_VAL1
and ET_VAL2
". Similarly, testing for a flag to be set should happen with a comparison operator, IMO. &
is the logical operation that needs to be done, but "flags
and ET_VAL1
" doesn't look like a test at all.
See my answer to this other question for my way of defining bit flag sets: https://stackoverflow.com/a/41516273/7328782
Upvotes: 0
Reputation: 42072
Not a direct answer to your question but, have you considered using std::bitset<N>
? I find it a convenient approach to defining and working with flags. For example:
#include <iostream>
#include <bitset>
using Flag = std::bitset<3>;
const Flag FOO("001");
const Flag BAR("010");
const Flag BAZ("100");
int main() {
Flag thing("011");
if((thing & FOO) == FOO) {
std::cout << "thing has foo\n";
} else {
std::cout << "thing does not have foo\n";
}
if((thing & BAR) == BAR) {
std::cout << "thing has bar\n";
} else {
std::cout << "thing does not have bar\n";
}
if((thing & BAZ) == BAZ) {
std::cout << "thing has baz\n";
} else {
std::cout << "thing does not have baz\n";
}
}
Sample output:
$ g++ example.cpp -std=c++14 -Wall -Wextra
$ ./a.out
thing has foo
thing has bar
thing does not have baz
For more information on std::bitset<N>
in cppreference.com, where it is described as:
The class template bitset represents a fixed-size sequence of N bits. Bitsets can be manipulated by standard logic operators and converted to and from strings and integers.
Upvotes: 1
Reputation: 505
You could create an array of bools and place that within a struct , making the final struct 'typesafe', with methods to set and modify if you are working in C++.
Upvotes: 0