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?
Asked
Active
Viewed 2,964 times
10

user1899020
- 13,167
- 21
- 79
- 154
-
There shouldn't be a difference you might have to cast to an int that's about it – aaronman Sep 14 '13 at 16:38
-
Some of the answers to this question you might possibly find of interest: [How do you set, clear and toggle a single bit in C?](http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c). – DavidRR Sep 14 '13 at 18:35
1 Answers
16
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 { };

Konrad Rudolph
- 530,221
- 131
- 937
- 1,214
-
2`That C++ doesn’t provide this out of the box is an oversight, in my opinion.` Enums are not bit fields. They are enums. – Lightness Races in Orbit Sep 14 '13 at 17:53
-
4@LightnessRacesinOrbit You seem to be claiming that using enums for bit flags is not a widely-used, established pattern in C++. Incidentally, C# goes even further and provides *explicit* support for treating certain enums as bit flags. – Konrad Rudolph Sep 14 '13 at 19:38
-
1I never claimed that it wasn't a widely-used or established pattern. My point is that it shouldn't be, because that is not what enums are in C++. That ORing them is not built-in in C++ only re-inforces that. I'm very pleased that C# has its own version of this language feature with different semantics, but C# is not C++. – Lightness Races in Orbit Sep 15 '13 at 10:45
-
3@Lightness But *why* shouldn’t it be? It’s a very practical idiom, I don’t see the problem. At best you could say that it’s mixing interface and implementation, but that’s pure over-engineering, and can also be trivially mitigated by providing convenience functions, as outlined in the code comment in my answer. – Konrad Rudolph Sep 15 '13 at 11:04
-
Why shouldn't it be? I can't answer that. All I can tell you is how C++ _is_ and, as the `enum` feature stands in C++, that `op|` is not built-in for scoped enums is not an oversight: it is consistency in action. – Lightness Races in Orbit Sep 15 '13 at 13:24
-
3@LightnessRacesinOrbit: Check the wording about enum ranges. It explicitly extends the range so that enum values OR-ed together are in range, too. No coincidence, the CWG explicitly intended that. (October 2004, Redmond, IIRC). I would like a `enum class Foo { operator| = default; }` syntax. – MSalters Sep 15 '13 at 23:36
-
@MSalters: Okay I concede that and submit that it's another example of the CWG breaking the C++ paradigm in small ways over the last few years, and doing so inconsistently. – Lightness Races in Orbit Sep 16 '13 at 08:58
-
1@LightnessRacesinOrbit: Your opinion, of course. The CWG considered it an established paradigm back then, and TBH I've seen enums used like that in Bell Labs code from ~1985. Besides your opinion, I've yet to see any clear indication what enums _should_ be and especially _why_. What benefit is achieved banning the use of enums for that purpose, and does that justify breaking reasonable code that's compiled for decades? – MSalters Sep 16 '13 at 12:50
-
@MSalters: First let's break apart the strawman in your argument: who said anything about banning anything? – Lightness Races in Orbit Sep 17 '13 at 09:10
-
1@LightnessRacesinOrbit: You, in all comments, argue how C++ should be. If the CWG had put your opinion in the standard - instead of "breaking the C++ paradigm" - then enums as bitfields would have been effectively banned because you couldn't count on them having the necessary range to represent all combinations. – MSalters Sep 17 '13 at 09:48
-
@MSalters: You can hardly claim that this means I'm suggesting "banning them". All we're doing here is debating whether the missing `op|` is really an "oversight". – Lightness Races in Orbit Sep 17 '13 at 14:04
-
1@LightnessRacesinOrbit The argument is quite logical though: CWG explicitly introduced wording to make enums usable as flags. Enum classes, which are generally meant to *replace* enums, are *not* usable for flags out-of-the-box (without jumping through casting hoops), even though they contain the same wording (regarding size) to enable their use for flags. That is at least inconsistent, and does strongly suggest oversight. – Konrad Rudolph Sep 17 '13 at 14:21
-
2Let me phrase it stronger: Considering all the work done so that `operator|` gives a value in range, it is rather surprising that `operator|` is missing. – MSalters Sep 17 '13 at 14:34