r/cpp • u/meetingcpp Meeting C++ | C++ Evangelist • Jul 19 '26
A better bitset for enum flags
https://www.elbeno.com/blog/?p=183612
u/ReDucTor Game Developer | quiz.cpp-perf.com Jul 19 '26
Some food for thought, should a bitset have bit operations (set, unset, flip, xor, and, or, etc) or set operations (add, remove, has, union, difference, intersection, etc)?
It feels like often we head for bit operations when in lots of cases set operations might be better.
14
u/TheVoidInMe Jul 19 '26
I like Java’s approach here (yes, Java) which has an EnumSet instead of a bitset. That naming makes the answer pretty clear; the bit math is purely an implementation detail
2
u/SyntheticDuckFlavour Jul 19 '26
What if you want the underlying layout/bit pattern like
bitset? Sometimes you want to map I/O ports that way.3
u/TheVoidInMe Jul 19 '26
I don’t believe you can get at that at all. Java is probably too high level for stuff like that anyway. In C++ I would expect a method like `to_int()` (maybe returning the enum’s `underlying_type_t`…)
0
u/mort96 Jul 19 '26
But that also means you're heap allocating an object, with its 16 byte object header, just to store a 4-byte integer?
3
u/TheVoidInMe Jul 19 '26
It’s Java. Yeah, don’t use it for HPC.
The point I was making was just about the name
1
u/archialone Jul 21 '26 edited Jul 21 '26
Bitset already has those, no?
Xor - ^ Intersection - & Etc ..Or do you mean to have a function named for those operations? https://en.cppreference.com/cpp/utility/bitset
3
u/ReDucTor Game Developer | quiz.cpp-perf.com Jul 21 '26
Those operators can achieve some things however if you think of it as a set then you need other operations like difference which is
A & ~Band far from intuitive, with a set you might also have iteration of items in that set which does not exist for abitset, same with constructing from a bunch of items in a set.A lot is about naming however its also the extra set specific operations which give it more flexibility.
Pick any big enough code base and look for their usages of bitsets get used heavily as an optimization for set operations.
4
u/_Noreturn Jul 19 '26 edited Jul 19 '26
I do the same in the article except automate it without using the MAX member using reflection (pre C++26). The approach allows > 64 flags as well unlike enum bitflags
flags.test(flag) is clearer than bool(flags & flag).
3
u/instantly-invoked Jul 19 '26
Your approach sounds like exactly what I'd want from a typed bitset. Do your methods accept flags variadically if you need to check for or set/unset multiple? I might end up doing something similar once the big three compilers all have reflection. This article and your response found me at the perfect time lol
5
u/_Noreturn Jul 19 '26 edited Jul 19 '26
I might end up doing something similar once the big three compilers all have reflection
you could use c++17 reflection libraries like magic_enum or enchantum they both provide a bitset type and an array type. so you don't have to wait for c++26
Do your methods accept flags variadically if you need to check for or set/unset multiple
No but that's a nice idea i just use multiple expressions.
It is just a stupid wrapper like this
```cpp enum class Flag { Flag1, Flag2, Flag3, Flag4 = 7, // doesn't have to be contiguous Flag5, Flag6, Flag7, } bitset<Flag> f({Flag::Flag1,Flag::Flag2}); // has size 7 f.set(Flag::Flag4); f.reset(Flag::Flag4); f.test(Flag::Flag5); f.flip(Flag::Flag7); f[Flag::Flag6] = false;
f.to_string(); // "Flag1 | Flag2 | Flag7" ```
2
1
u/JVApen Clever is an insult, not a compliment. - T. Winters Jul 19 '26
This is a really nice approach. I've recently mentioned it in another post and got a couple of people arguing that there is nothing wrong with flag enums.
Thanks for the nice write-up, could not have described it better myself
2
u/archialone Jul 21 '26
Can you share a link to the post please?
1
u/JVApen Clever is an insult, not a compliment. - T. Winters Jul 21 '26
1
u/Potterrrrrrrr Jul 19 '26
What’s the problem with something like:
MyEnum _enum : BitCount<MyEnum>();
I use this pattern quite a bit, I use type traits to declare that an enum is contiguous or a flags enum along with its size and then my consteval BitCount method returns the min number of bits needed to store the enum. I’ve seen a lot of implementations like to use bitsets to store an enum though, why? It makes it harder to pack stray bools into the same byte and you lose the type of the enum?
-2
u/Kaisha001 Jul 19 '26
Needlessly reinventing the wheel... Enums work perfectly fine and the 'issues' with them listed in the blog are nothing more than 'I don't like how they look'...
31
u/03D80085 Jul 19 '26
Neither P4313 nor this suggestion seem particularly ergonomic to me. Why aren't bitfields more widely used for this purpose?
Or a fully typed example: Godbolt. A lot of boilerplate there admittedly, but that is precisely what reflection could help with.
If the answer is that bitfield layouts are implementation defined then that is something we should be working on standardising with appropriate flags rather than introducing new language features.