C++ Logo


Advanced search

Re: [std-proposals] Revision 1 of scoped enum enhancements (Answer to Sebastian Wittmeier)

From: Henry Miller <hank_at_[hidden]>
Date: Wed, 09 Aug 2023 15:13:39 -0500
On Wed, Aug 9, 2023, at 10:01, Alexander Christensen via Std-Proposals wrote:

>> The templated class in its current form does not support bitfields, where one flag needs more than one bit.

> Or, if you (or others) think it better, the Bitmask class itself could
> be extended with a method accepting a value of idempotent type:
> enum class Website { Facebook = 1, Google = 2 };
> constexpr std::Bitmask<Website> Fb_Goog = Website::Facebook | Website::Google;
> std::Bitmask<Website> MyBitmask;
> MyBitmask.add_mask(Fb_Goog);
>> For bit-masking enums often constant flag-combinations are defined, including no flags, which equals 0 in the underlying type or all flags, which not necessarily (depending on whether the bits are all used) equals -1.
> How about if the class gets a method `add_all_flags()` which just set
> the private member to -1? I am implicitly assuming the underlying type
> to always be unsigned, because inside my head that makes the most sense
> - perhaps this assumption is wrong?

This assumption is wrong, at least in my domain. I often have protocols where the bit flags are just a few bits in the middle of a byte, and with higher and lower values used in some other field. Worse sometimes these fields can start in the middle of one byte, and cross into the next (but the total is still less than 8 bits). As such I'd like the compiler to know what bit range the flags are in and set the out of range values to all zero so I can to a bitwise or to get the values out. Even this doesn't quite work as I'd want to extra those bits from a message and the other bit may not be zero - maybe I need a clear all reserved bits class member?

I'm inclined to say that add_all_flags should not be implemented. If a bit field value is in range, but doesn't have a meaning assigned when I build, it seem unlikely that it is defined - and my code isn't recompiled - whatever the new meaning is will be correct when set. Most of the time new flags to an enum add new behavior that I wouldn't want in old code (or at least that is my impression - maybe this is wrong).

Now if instead we can add functions to an enum, then I can make it do what I want. Or maybe add_all_flags() is defined by default, but I'm allowed to give a different definition to any enum if the default isn't correct. (both of the above are interesting ideas, but I can think of reasons I'd object to both and so I'm not sure if overall I favor it)

> The reason why I propose a template meta-function which checks that a
> scoped enum does not contain a zero value, is because I think for the
> reasons of type safety such a value should always be forbidden. This is
> the distinction between using an enum for bitmasking or for other
> purposes. I also choose to forbid adding an integer value to the
> bitmask class.
> These are just design choices. Not necessarily the best option.?
> -----
>> When measuring the cardinality to add to the end or create end marker as =cardinality+1.
> Maybe this is just me, but I don't quite understand why having an end
> marker is useful. Is this because it makes it easier to implement an
> iterator?

An end iterator is for some enums a useful thing to have. For others it makes no sense, but sometimes I'm iterating over all values in the enum. (the cases where I do this the enum is not flag values so setting to -1 wouldn't work)

> If a scoped enum has two values, and one of them is 0, then cardinality
> must still equal 2. And if an end marker should exist, it would have to
> be the third value inside the enum.
> Or perhaps you mean to create a different type, e.g.
> `std::enum_end_marker<T>`, which makes a calculation based on
> cardinality, for some other purpose?
>> Perhaps the end should not be defined as an enum value itself.
> I agree on this. It would make code significantly more difficult to
> read, ie. I think it would only add unnecessary complexity. I think C++
> is sufficiently complicated already. :)

I think the important thing to take away is there are many different uses for an enum. The question is which uses are common enough that it is useful to have extra language support; and how can we add that support without breaking or make too much worse the other uses for enums.

Received on 2023-08-09 20:14:01