C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::enum_max and std::enum_min

From: Alejandro Colomar <alx.manpages_at_[hidden]>
Date: Mon, 10 Jul 2023 14:40:17 +0200
Hi Jonathan,

On 2023-07-10 13:28, Jonathan Wakely via Std-Proposals wrote:
> On Mon, 10 Jul 2023 at 10:08, Sebastian Wittmeier via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Hi Alex,
>>
>> I think you misunderstood.
>>
>> Jonathan's INT_MIN / INT_MAX do not return 1 or 16, respectively, for
>> enums.
>>
>> Quite the opposite, Jonathan pointed out that the existing values INT_MIN
>> / INT_MAX can be stored in MyEnum, so 1 or 16 are _not_ the minimum or
>> maximum possible value for the example.
>>
>
> Precisely.


On 2023-07-10 10:02, Jonathan Wakely via Std-Proposals wrote:
>> I propose that:
>>
>> std::enum_max<MyEnum>
>>
>> would evaluate to 16, and that:
>>
>> std::enum_min<MyEnum>
>>
>> would evaluate to 1.
>>
> Why?
>
> This is perfectly valid:
> auto e = (MyEnum)INT_MAX;
> And similarly for INT_MIN and 0 etc.

This had confused me. I was like, is this some of this crazy magic
that C++ has for enums to make them separate types from integers and
I didn't know it? But no. :D


> Any proposal related to the "min" and "max" of enums needs to
> discuss the valid values of the enumeration type.

[I'll talk about the C-compatible part, which is what I'm interested about;
I don't really care about C++'s enum class and strong typing features]

Regardless of the maximum and minimum values that are supported by the
underlying type of an enum, it is always useful to be able to know 3 things
of an enumeration:

- Highest defined enumerator value.
- Lowest defined enumerator value.
- Count of enumerators in the enumerator list.
- Are all the enumerators consecutive?

This is very often useful, for example, for creating an array that uses
that info for the size:

 int arr[__builtin_enum_count(enum foo)];

I don't like the idea of proposing this kind of things to the standard
directly, but rather propose it for a compiler, and only if it proves to
be a good API then propose standardization. So, if anyone involved in GCC
or Clang thinks some of

 __builtin_enum_max(enum_type)
 __builtin_enum_min(enum_type)
 __builtin_enum_count(enum_type)
 __builtin_enum_is_consecutive(enum_type)

could be useful, feel free to take the idea and implement it.

Regarding your concerns that enumerations can be used as flags, I've long
thought that there are basically two very different uses for an enum:

- actual enumerations; only values within the enumerator list are valid
- flags; composition of enumerators are also valid; normally, the
   enumerators are powers of two.

An idea floats my mind from time to time, that having a [[flags]]
attribute for such an enum would be useful to mark pow-of-2 cases. It
could make that the enumerators are prev<<1 if the value is unspecified,
instead of prev++ that is default for enums.

However, I was never convinced by such idea because removing attributes
should produce working code, and having the default values of an enum
change depending on the attribute would be problematic. An alternative
idea would be to use 'unsigned enum', since flags lists should be
unsigned, to allow bitwise operations without UB.

>
>
>>
>>
>> This has often used practical applications:
>>
>> MyEnum wolpertinger = eMonkey | eFish | eGoat | eFrog; // 30 > 16
>>
>>
>>
>> e.g. if like in the example the enum values are given as power of 2 flags,
>> which can be added/ORed.
>>
>
> Yup. I don't see why you would define power of two enumerators unless you
> intend their bitwise OR to be valid, which will produce a higher value than
> the "max" (although the bitwise OR of all the enumerators uses the same
> number of bits as the highest enumerator). So the example in the "proposal"
> isn't even self-consistent IMHO.

Yup, the example used in the "proposal" is quite broken; agree.

Cheers,
Alex

-- 
<http://www.alejandro-colomar.es/>
GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5

Received on 2023-07-10 12:40:21