Enum class : bitwise operations?

Started by
17 comments, last by Juliean 11 years ago

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

Yup, thats how I've got it, too. As Álvaro pointed out correctly, casting from/to the obvious data type shouldn't be the problem, and since I trust phil_t that casting should be almost free, there is really no issue with that method whatsover.

Advertisement

How is casting to int a problem if the enum is defined to use int as the underlying type?

To make things completely tight one could use (not tested but documentation suggests it should work):



static inline ENUM_DrawElements operator | (ENUM_DrawElements a, ENUM_DrawElements b) 
{ 
   return static_cast<ENUM_DrawElements>(
      static_cast<std::underlying_type<ENUM_DrawElements>::type>(a) | 
      static_cast<std::underlying_type<ENUM_DrawElements>::type>(b)); 
}
A bit overkill in this particular scenario, but there are cases where types have to be changed during development. Besides, it's nice to know there is something to get the base type in the general case...

How is casting to int a problem if the enum is defined to use int as the underlying type?

What if the underlying type is not an int?

Well, in your own example you definitely fixed the type to int. If the type is not known or is likely to change there is still my suggestion.

Well, in your own example you definitely fixed the type to int.

And what does this little side note have to do with my copy-pasted code?

Seriously though - it was just poor wording on my part. I'm glad it was picked up, but the interpretation of its meaning is misplaced here.


How is casting to int a problem if the enum is defined to use int as the underlying type?


What if the underlying type is not an int?


I am confused. My post was a comment on the post right above it, which showed some code which specified int as the underlying type and then used a cast to int.

I do like BitMaster's code, though, despite how verbose it is. Instead of overloading any operators, I would prefer to provide a function to test if some bits are active. That function can be a template so it works for all enum types automatically (a feature that was requested by The King2), and then you have to add `typename', making the code even uglier.
#include <iostream>
#include <type_traits>

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

// Returns whether the bits set in x contain the bits set in y
template <typename T>
bool contains_bits(T x, T y) {
  return (static_cast<typename std::underlying_type<T>::type>(x)
          & static_cast<typename std::underlying_type<T>::type>(y))
    == static_cast<typename std::underlying_type<T>::type>(y);
}

int main() {
  WindowBorders wb = WindowBorders::LeftBottom;
  if (contains_bits(wb, WindowBorders::Left))
    std::cout << "Yay!\n";
}


I do like BitMaster's code, though, despite how verbose it is. Instead of overloading any operators, I would prefer to provide a function to test if some bits are active. That function can be a template so it works for all enum types automatically (a feature that was requested by The King2), and then you have to add `typename', making the code even uglier.

Since I've already writte a set of bithelper-classes, this would fair quite well, actually. But is there any chance to use template specialisation here so I don't need a seperate function? It's just a minor annoyance, though...


namespace acl
{
	namespace bit
	{
		template<typename b>
		bool contains(b left, b right)
		{
			return (left & right) == right;
		}

		template <typename T>//can't we use template specialistion here so we can name this "contains" too?
		bool enum_contains(T x, T y) {
		  return (static_cast<typename std::underlying_type<T>::type>(x)
				  & static_cast<typename std::underlying_type<T>::type>(y))
			== static_cast<typename std::underlying_type<T>::type>(y);
		}
	}
}

But is there any chance to use template specialisation here so I don't need a seperate function?

Of course there is, but it gets even uglier...
template <typename T>
bool contains_bits(T x, T y, std::true_type) {
  return (static_cast<typename std::underlying_type<T>::type>(x)
          & static_cast<typename std::underlying_type<T>::type>(y))
    == static_cast<typename std::underlying_type<T>::type>(y);
}

template <typename T>
bool contains_bits(T x, T y, std::false_type) {
  return (x & y) == y;
}

template <typename T>
bool contains_bits(T x, T y) {
  return contains_bits(x, y, std::integral_constant<bool, std::is_enum<T>::value>());
}

Of course there is, but it gets even uglier...

Gee wiz, thanks! I won't say I like it when code is ugly but at least I've got everything hid away in my beatiful convienient namespace and seperate bit-helper file I'm going to touch every decade or so, that it doesn't even matter.

This topic is closed to new replies.

Advertisement