It was my deep hidden dream, to replace all enums in Urho.
Impossible w/o breaking a lot of legacy things. Even replacement within the engine would be painful. If only we have automatic tool…
It could be just some python script or native tool tho. Just find and replace fixed list of entries.
Hmmm, maybe even header with defines… I’ve just started to like this idea.
It starts to get nasty when you convert to and from their fundamental type. You need explicit cast everywhere. They’re not called strongly typed enums for nothing.
And a bunch of code still relies on behavior similar to old enums.
What you’re seeking is closer to being called scoped enums. Which can be achieved with empty enums inside structs/namespaces. Or even constexpr variables at the cost of loosing warnings about unhandled enumerations in switch cases.
Either way, code doesn’t get prettier with strongly typed enums. I can tell you that.
My secret dream is to actually use enums instead of integer constants to get more type safety. For people with experience this may not be a problem, but for less experienced it is damn confusing when you see function taking int. Good luck guessing where from you should pull that int. The only downside is that enums which serve as flags need extra code to allow painless flag manipulation without extra casts:
#define URHO3D_TO_FLAGS_ENUM(t) \
inline t operator|(t a, t b) { return static_cast<t>(static_cast<size_t>(a) | static_cast<size_t>(b)); }\
inline t operator|=(t& a, t b) { a = static_cast<t>(static_cast<size_t>(a) | static_cast<size_t>(b)); return a; }\
inline t operator&(t a, t b) { return static_cast<t>(static_cast<size_t>(a) & static_cast<size_t>(b)); }\
inline t operator&=(t& a, t b) { a = static_cast<t>(static_cast<size_t>(a) & static_cast<size_t>(b)); return a; }\
inline t operator^(t a, t b) { return static_cast<t>(static_cast<size_t>(a) ^ static_cast<size_t>(b)); }\
inline t operator^=(t& a, t b) { a = static_cast<t>(static_cast<size_t>(a) ^ static_cast<size_t>(b)); return a; }\
inline t operator~(t a) { return static_cast<t>(~static_cast<size_t>(a)); }
Edit: By the way this also sucks somewhat because macro has to be used on the enum outside of any namespace in order to allow user code not from Urho3D namespace to use these operators.
Yes i am aware of these tricks. Not sure how well they would play with backwards compatibility so not suggesting any of that. What do you thin about this solution? Is it feasible to have it some time?
In first case enum would be accessed as DrawableFlags::ANY + FlagSet<DrawableFlags> and in second case it would be Drawable::ANY + FlagSet<Drawable::Flags>.
This only requires changing parameter types to FlagSet<... while any other code does not need modifications. Including user code. This could be a perfect middle ground for backwards compatibility for now.
As I currently being tutored, using class where POD can do same thing is BAD. Don’t blame me too much though - I’m still openning amusing world of gamedev and every hour of it is fascinating.