On 6/9/2018 at 5:51 PM, TheComet said:
As far as I can tell, using enum class is more a hindrance than a useful tool with flags.
That's correct. The purpose of strongly typed enums was to allow strict enforcement of enumerations. It prevents things like (Blue+5) which may not be a valid enumeration value, or (Walking | Yellow) which may not be a valid combination. You can list all the states in your FSA and be sure you're not getting unexpected values that aren't enumerated at all.
Flag operations are directly contrary to the strong type since they're asking to be treated as bit patterns rather than enumerations. That is, you are not using them like a strongly typed enumeration where you're only dealing with the items on the list, instead you're treating them as a pattern of bits.
One pattern that can help keep them within a name is to keep them as weakly typed values inside a namespace:
namespace MyFlags {
enum MyFlags : int {
none = 0,
foo = 1<<0,
bar = 1<<1,
baz = 1<<2,
thing1 = 1<<3,
thing2 = 1<<4,
...
};
}
Alternatively you can use a mix of templates and/or macros to generate the expected operations for your flags. There are plenty of examples of it online that compile away to constant expressions that are optimized back down to bitfield operations, my first search pulls up four different github projects for it and a bunch of stackoverflow and similar postings.
Just remember that you aren't using the feature the way it was designed.
If you want bit manipulation then use bit manipulation. If you want a strong enumeration where you're only dealing with the enumerated values, use an enum class. They're different use cases and they have different meanings and different requirements.