Treating enum
s as flags works nicely in C# via the [Flags]
attribute, but what's the best way to do this in C++?
For example, I'd like to write:
enum AnimalFlags
{
HasClaws = 1,
CanFly =2,
EatsFish = 4,
Endangered = 8
};
seahawk.flags = CanFly | EatsFish | Endangered;
However, I get compiler errors regarding int
/enum
conversions. Is there a nicer way to express this than just blunt casting? Preferably, I don't want to rely on constructs from 3rd party libraries such as boost or Qt.
EDIT: As indicated in the answers, I can avoid the compiler error by declaring seahawk.flags
as int
. However, I'd like to have some mechanism to enforce type safety, so someone can't write seahawk.flags = HasMaximizeButton
.
As above(Kai) or do the following. Really enums are "Enumerations", what you want to do is have a set, therefore you should really use stl::set
Here's an option for bitmasks if you don't actually have a use for the individual enum values (ex. you don't need to switch off of them)... and if you aren't worried about maintaining binary compatibility ie: you don't care where your bits live... which you probably are. Also you'd better not be too concerned with scoping and access control. Hmmm, enums have some nice properties for bit-fields... wonder if anyone has ever tried that :)
We can see that life is great, we have our discrete values, and we have a nice int to & and | to our hearts content, which still has context of what its bits mean. Everything is consistent and predictable... for me... as long as I keep using Microsoft's VC++ compiler w/ Update 3 on Win10 x64 and don't touch my compiler flags :)
Even though everything is great... we have some context as to the meaning of flags now, since its in a union w/ the bitfield in the terrible real world where your program may be be responsible for more than a single discrete task you could still accidentally (quite easily) smash two flags fields of different unions together (say, AnimalProperties and ObjectProperties, since they're both ints), mixing up all yours bits, which is a horrible bug to trace down... and how I know many people on this post don't work with bitmasks very often, since building them is easy and maintaining them is hard.
So then you make your union declaration private to prevent direct access to "Flags", and have to add getters/setters and operator overloads, then make a macro for all that, and you're basically right back where you started when you tried to do this with an Enum.
Unfortunately if you want your code to be portable, I don't think there is any way to either A) guarantee the bit layout or B) determine the bit layout at compile time (so you can track it and at least correct for changes across versions/platforms etc) Offset in a struct with bit fields
At runtime you can play tricks w/ setting the the fields and XORing the flags to see which bits did change, sounds pretty crappy to me though verses having a 100% consistent, platform independent, and completely deterministic solution ie: an ENUM.
TL;DR: Don't listen to the haters. C++ is not English. Just because the literal definition of an abbreviated keyword inherited from C might not fit your usage doesn't mean you shouldn't use it when the C and C++ definition of the keyword absolutely includes your use case. You can also use structs to model things other than structures, and classes for things other than school and social caste. You may use float for values which are grounded. You may use char for variables which are neither un-burnt nor a person in a novel, play, or movie. Any programmer who goes to the dictionary to determine the meaning of a keyword before the language spec is a... well I'll hold my tongue there.
If you do want your code modeled after spoken language you'd be best off writing in Objective-C, which incidentally also uses enums heavily for bitfields.
Currently there is no language support for enum flags, Meta classes might inherently add this feature if it would ever be part of the c++ standard.
My solution would be to create enum-only instantiated template functions adding support for type-safe bitwise operations for enum class using its underlying type:
File: EnumClassBitwise.h
For convenience and for reducing mistakes, you might want to wrap your bit flags operations for enums and for integers as well:
File: BitFlags.h
Possible usage:
The "correct" way is to define bit operators for the enum, as:
Etc. rest of the bit operators. Modify as needed if the enum range exceeds int range.
Only syntactic sugar. No additional metadata.
Flag operators on integral type just works.
The C++ standard explicitly talks about this, see section "17.5.2.1.3 Bitmask types":
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf
Given this "template" you get:
And similar for the other operators. Also note the "constexpr", it is needed if you want the compiler to be able to execute the operators compile time.
If you are using C++/CLI and want to able assign to enum members of ref classes you need to use tracking references instead:
NOTE: This sample is not complete, see section "17.5.2.1.3 Bitmask types" for a complete set of operators.