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?
How to make enum class to work with the 'bit-or' feature?
Asked Answered
There shouldn't be a difference you might have to cast to an int that's about it –
Agnella
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?. –
Conduction
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 { };
That C++ doesn’t provide this out of the box is an oversight, in my opinion.
Enums are not bit fields. They are enums. –
Puzzlement @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. –
Wakashan
I 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++. –
Puzzlement
@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. –
Wakashan
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. –
Puzzlement @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. –
Harridan @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. –
Puzzlement
@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? –
Harridan
@MSalters: First let's break apart the strawman in your argument: who said anything about banning anything? –
Puzzlement
@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. –
Harridan
@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". –
Puzzlement @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. –
Wakashan
Let 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. –
Harridan © 2022 - 2024 — McMap. All rights reserved.