Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make enum class to work with the 'bit-or' feature?

Tags:

c++

enum-class

I usually use enum with the 'bit-or' or | together to allow an object has some options. How to make enum class to work with the 'bit-or' feature?

like image 511
user1899020 Avatar asked Sep 14 '13 16:09

user1899020


People also ask

Can I declare enum in class?

Declaration of enum in Java: Enum declaration can be done outside a Class or inside a Class but not inside a Method.

What is difference between enum and enum class?

Difference between Enums and Classes An enum can, just like a class , have attributes and methods. The only difference is that enum constants are public , static and final (unchangeable - cannot be overridden).

Can enum be used as base class for inheritance?

it is not possible. Enum can not inherit in derived class because by default Enum is sealed.

Can you put an enum in a class C++?

C++11 has introduced enum classes (also called scoped enumerations), that makes enumerations both strongly typed and strongly scoped. Class enum doesn't allow implicit conversion to int, and also doesn't compare enumerators from different enumerations. To define enum class we use class keyword after enum keyword.


Video Answer


1 Answers

You need to overload the operators for your enum class and implement them by casting to the underlying type:

enum class foo : unsigned {
    bar = 1,
    baz = 2
};

foo operator |(foo a, foo b) {
    return static_cast<foo>(static_cast<unsigned>(a) | static_cast<unsigned>(b));
}

… of course this could be generalised (using SFINAE and std::underlying_type). That C++ doesn’t provide this out of the box is an oversight, in my opinion.

Here’s how a general implementation might look like:

// Intentionally undefined for non-enum types.
template <typename T, bool = std::is_enum<T>::value>
struct is_flag;

template <typename T>
struct is_flag<T, true> : std::false_type { };

template <typename T, typename std::enable_if<is_flag<T>::value>::type* = nullptr>
T operator |(T lhs, T rhs) {
    using u_t = typename std::underlying_type<T>::type;
    return static_cast<T>(static_cast<u_t>(lhs) | static_cast<u_t>(rhs));
}

// … same for `&`, `~`. And maybe functions like `isset`, `set` and `unset`.

This implementation ensures that the overload is only found for enums that are actually acting as flags. To mark an enum as a flag, you need to specialise is_flag:

enum class a_flag : unsigned {
    foo = 0,
    bar = 1,
    baz = 2
};

template <> struct is_flag<a_flag> : std::true_type { };
like image 92
Konrad Rudolph Avatar answered Sep 22 '22 00:09

Konrad Rudolph