Enum class from c++11 standart


#1

What about using enum class instead identifiers in global namespace

Old:

enum MouseMode
{
    MM_ABSOLUTE = 0,
    MM_RELATIVE,
    MM_WRAP,
    MM_FREE,
    MM_INVALID
};

input->SetMouseMode(MM_FREE);

New:

enum class MouseMode
{
    Absolute = 0,
    Relative,
    Wrap,
    Free,
    Invalid
};

input->SetMouseMode(MouseMode::Free);

#2

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.


#3

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.


#4

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.


#5

You know, in my childhood, when I was working on my own game engine…
I was able to write this piece of code:


[damn, I got a stike of nostalgia and probably going looking at my old code]


#6

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?


#7

Just make bunch of static const MyEnum EN_VALUE = MyEnum::Value in special header, maybe?


#8

This is relatively small comparing to other important things.:smile:


#9

True. Let’s do Vulkan first.


#10

Damn! I need to replace my old GTX 580 soon then. LOL.


#11

Which is more kosher:

In Urho3D namespace:

enum class DrawableFlags
{
    UNDEFINED = 0x0,
    GEOMETRY = 0x1,
    LIGHT = 0x2,
    ZONE = 0x4,
    GEOMETRY2D = 0x8,
    ANY = 0xff,
};

Or in Drawable class:

enum Flags
{
    UNDEFINED = 0x0,
    GEOMETRY = 0x1,
    LIGHT = 0x2,
    ZONE = 0x4,
    GEOMETRY2D = 0x8,
    ANY = 0xff,
};

?

In first case enum would be accessed as DrawableFlags::ANY + FlagSet<DrawableFlags> and in second case it would be Drawable::ANY + FlagSet<Drawable::Flags>.


#12

I would opt for the enum class since so many things inherit from Drawable. Maybe call it DrawableKind, though?


#13

While on the topic of scoping. Is the uppercase necessary? I usually keep it with a capital letter for each word (including the first one).

As a bonus, since you can actually forward declare strongly typed enumerations. I’m guessing that would help to avoid including headers unnecessarily.

But still, using this for flags. I can’t say I’m very fond of it. Can also be achieved with:

struct DrawableKind
{
	enum Type {
		Undefined		= 0x0,
		Geometry		= 0x1,
		Light			= 0x2,
		Zone			= 0x4,
		Geometry2d		= 0x8,
		Any				= 0xff
	};
	// not sure this is necessary
	DrawableKind() = delete;
};

#14

FlagSet<DrawableKind::Type> feels like overkill :slight_smile:

Edit:
Actually im thinking maybe best approach for starters would be:

enum DrawableFlags
{
    DRAWABLE_UNDEFINED = 0x0,
    DRAWABLE_GEOMETRY = 0x1,
    DRAWABLE_LIGHT = 0x2,
    DRAWABLE_ZONE = 0x4,
    DRAWABLE_GEOMETRY2D = 0x8,
    DRAWABLE_ANY = 0xff,
};

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.


#15

BTW it’s not bad idea even regardless of enum class.
Parameters like unsigned flags suck.

Actually, DrawableFlags are needed only for nice querying.
In real classes only one bit is set.


#16

From DOD point of view simple enum is superior to enum class.


#17

Could you explain? I don’t get how DOD is ever related to enum vs enum class choose.


#18

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.


#19

You’re not making any sense tho. POD?


#20

Plain old data. As you probably know, enum is essentially int.