Jump to content
  • Advertisement
Sign in to follow this  
Juliean

Enum class : bitwise operations?

This topic is 1928 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

 

I've recently converted all my enums to strongly typed enums, like this:

 

enum class WindowBorders : unsigned char {
    None            = 0x00,
    Left            = 0x01,
    Right            = 0x02,
    Bottom            = 0x04,
    LeftBottom        = 0x05,
    RightBottom        = 0x06,
};

 

Now these work as flags, and previously I could have been checking if a variable contained one of those flags by coding:

 

unsigned char m_cBorder = LeftBottom;
if( (m_cBorder & Left) == Left )
//left border was clicked

Now this won't work anymore, I have to treat LeftBottom and RightBottom as seperate cases, while they essentially are just an addition of bottom and eigther left or right border, and also work that way. That causes a lot of unecessary code for my window object. The (german) compiler gives me somemessage about "&" only working for enums without a range restriction (?). Is this really impossible to achieve or is there some way to still do this?

Edited by The King2

Share this post


Link to post
Share on other sites
Advertisement

You can define a | and & operator for your enum (static_cast'ing them to ints then back to the enum type after applying the operation). To avoid re-typing the same code for each different enum type, you can put it in a macro or something.

Share this post


Link to post
Share on other sites

Well it should work, did you tried debugging to see if m_cBorder has the right bits set? Im pretty sure the problem isn't in the code posted above.

Edited by jbadams
Restored post contents from history.

Share this post


Link to post
Share on other sites

Well it should work, did you tried debugging to see if m_cBorder has the right bits set? Im pretty sure the problem isn't in the code posted above.

 

The code included above does work, having just "enum WindowBorders". That is the code that will fail:

 

WindowBorders m_cBorder = WindowBorders::LeftBottom;
if( m_cBorder & WindowBorders::Left) == WindowBorders::Left) //won't compile here

It simply won't compile, so there is no need/option for debugging.

 

You can define a | and & operator for your enum (static_cast'ing them to ints then back to the enum type after applying the operation). To avoid re-typing the same code for each different enum type, you can put it in a macro or something.

 

Since strongly typed enums can't have an operator overloaded, I assume you generally suggest eigther writing a macro or templated global function? How costly are static_casts anyway? Because there could be potentially a lot of checks throughout my code. Given this setting I'd somehow doubt the benefit of strongly typed enums over the overhead of "simulating" a bitwise operator... what would you rather choose?

Share this post


Link to post
Share on other sites

Well you could solve the issue by using #define's instead

 

#define WINBORDER_NONE 0x00

... ect

 

Why would you need strongly typed enums? Using your old code will work regardless of the type used (int, short, char, byte ect), no need to overcomplicate things rolleyes.gif

Edited by jbadams
Restored post contents from history.

Share this post


Link to post
Share on other sites

I'm not a big fan of #defines, as far as there are better alternatives really. It would work for normal enums so thats not the problem. I choose to go with strongly typed enums for multiple reasons:

 

- It makes code much more clear. Consider this:

 

void Cursor::ChangeState(CursorState newState)
{
	m_state = newState;
	switch(m_state)
	{
	case CursorState::IDLE:
		m_sFileName = L"CursorIdle.png";
		m_offsetX = 0;
		m_offsetY = 0;
		break;
	case CursorState::DRAG_V:
		m_sFileName = L"CursorDragV.png";
		m_offsetX = 16;
		m_offsetY = 16;
		break;
	case CursorState::DRAG_H:
		m_sFileName = L"CursorDragH.png";
		m_offsetX = 16;
		m_offsetY = 16;
		break;
	case CursorState::DRAG_LD:
		m_sFileName = L"CursorDragLD.png";
		m_offsetX = 16;
		m_offsetY = 16;
		break;
	case CursorState::DRAG_RD:
		m_sFileName = L"CursorDragRD.png";
		m_offsetX = 16;
		m_offsetY = 16;
		break;
	}
}

over this:

void Cursor::ChangeState(UINT newState)
{
	m_state = newState;
	switch(m_state)
	{
	case IDLE:
		m_sFileName = L"CursorIdle.png";
		m_offsetX = 0;
		m_offsetY = 0;
		break;
	case DRAG_V:
		m_sFileName = L"CursorDragV.png";
		m_offsetX = 16;
		m_offsetY = 16;
		break;
	case DRAG_H:
		m_sFileName = L"CursorDragH.png";
		m_offsetX = 16;
		m_offsetY = 16;
		break;
	case DRAG_LD:
		m_sFileName = L"CursorDragLD.png";
		m_offsetX = 16;
		m_offsetY = 16;
		break;
	case DRAG_RD:
		m_sFileName = L"CursorDragRD.png";
		m_offsetX = 16;
		m_offsetY = 16;
		break;
	}
}

Its not something that absolutely needs to be, but I think in the first code it everything is much clearer, extending to how the m_state variable is declared (CursorState instead of UINT) etc...

 

- I won't possibly ever run in a name clash for these enums.

 

- There is no possibility to asign a wrong value. Thing is, that like you said, the old code works regardeles of the actual type used, I don't like that very much. I can pass in My NoResize - flag from the WindowStyleFlags to the CursorState, which isn't possible with strongly typed enums.

 

Over all I just tend to prefern them after I read about them some while ago, I just decided to implement them tody. Surely the old code works, and I wouldn't need them, the "enum class" makes things just more clean, in my opinion, and my goal after getting code to work is now to polish it up... except for that bitwise-thingy, that is :/

Edited by The King2

Share this post


Link to post
Share on other sites

Since strongly typed enums can't have an operator overloaded, I assume you generally suggest eigther writing a macro or templated global function? How costly are static_casts anyway? Because there could be potentially a lot of checks throughout my code. Given this setting I'd somehow doubt the benefit of strongly typed enums over the overhead of "simulating" a bitwise operator... what would you rather choose?

 

There is an example of what I meant here, a few answers down:

http://stackoverflow.com/questions/1448396/how-to-use-enums-as-flags-in-c

 

I'm pretty sure static_cast from an int to enum (or vice versa) would just be compiled away, so it should be free.

Share this post


Link to post
Share on other sites

Ah, I see, that worked. Thanks! A lot better again, thankfully. Now I only gotta find a way to automatice this for all enums and, aditionally possibly hide away this:

(border & WindowBorders::Bottom) == WindowBorders::Bottom

And other repetitive bit-checks into some sort of helper functions. Should be easiely doable, though.

Share this post


Link to post
Share on other sites

Here's what I'm doing to somewhat "automate" the process. You could write a macro to further cut down code.

 

enum ENUM_DrawElements : int {
GD_DRAW_ELEMENT_NONE = 0,
GD_DRAW_ELEMENT_STATIC_GEOMETRY = 1,
GD_DRAW_ELEMENT_DYNAMIC_GEOMETRY = 2,
GD_DRAW_ELEMENT_ENTITIES = 4,
GD_DRAW_ELEMENT_EDITORFUNCTIONS = 8,
//...
};


static inline ENUM_DrawElements operator|(ENUM_DrawElements a, ENUM_DrawElements b) { return static_cast<ENUM_DrawElements>(static_cast<int>(a) | static_cast<int>(b)); }

 

 

You can now use bitwise or on members of ENUM_DrawElements: GD_DRAW_ELEMENT_STATIC_GEOMETRY | GD_DRAW_ELEMENT_ENTITIES | ...
 
NOTE: you do have to mind possible precision issues, though - casting to int is limiting the precision to 32 bits.

Share this post


Link to post
Share on other sites
How is casting to int a problem if the enum is defined to use int as the underlying type?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!