This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115g. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-16


2932. Value range of empty enumeration

Section: 9.7.1  [dcl.enum]     Status: review     Submitter: Benjamin Sch.     Date: 2024-08-31     Liaison: EWG

(From submission #604.)

Consider:

  enum E { };
  constexpr auto x = static_cast<E>(-1);

It is unclear whether the hypothetical integer type for E is a signed integer type of width 1 or an unsigned integer type of width 0, which does not have a signed counterpart and thus does not exist. The former choice makes the example well-formed, the latter one ill-formed. Before P1236, the specification was clear.

Proposed resolution:

Change in 9.7.1 [dcl.enum] paragraph 8 as follows:

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, the values of the enumeration are the values representable by a hypothetical integer type with minimal width M such that all enumerators can be represented; if if the enumerator-list is empty or all enumerators have value 0, the values of the enumeration consist of the single value 0 and M is 0. The width of the smallest bit-field large enough to hold all the values of the enumeration type is the maximum of 1 and M. [ Note: It is possible to define an enumeration that has values not defined by any of its enumerators. -- end note ] If the enumerator-list is empty, the values of the enumeration are as if the enumeration had a single enumerator with value 0. [Footnote: ... ]

CWG 2024-10-25

A value needs at least one bit to be represented, which always allows to differentiate two values. Thus, having the "values of an enumeration" be a single value makes no sense.

The wording in C++17 [dcl.enum] p8 said:

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, for an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values in the range bmin to bmax, defined as follows: Let K be 1 for a two's complement representation and 0 for a ones' complement or sign-magnitude representation. bmax is the smallest value greater than or equal to max(|emin| - K, |emax|) and equal to 2M - 1, where M is a non-negative integer. bmin is zero if emin is non-negative and -(bmax + K) otherwise. The size of the smallest bit-field large enough to hold all the values of the enumeration type is max(M, 1) if bmin is zero and M + 1 otherwise. It is possible to define an enumeration that has values not defined by any of its enumerators. If the enumerator-list is empty, the values of the enumeration are as if the enumeration had a single enumerator with value 0.

If there is a single enumerator with value 0, emin = 0 and emax = 0. A two's complement representation is now required, thus K=1. bmax is 0 with M = 0. bmin is 0.

CWG 2025-11-08

The wording in the proposed resolution restores the C++17 situation. However, both clang and gcc agree that the values of an empty enumeration or one with all enumerators having value 0 are actually 0 and 1, reflecting the single bit of storage needed for the representation. CWG observed that empty classes also occupy one byte of storage, even though they hold no values at all.

EWG should decide whether to keep the C++17 rule or adjust the wording to reflect the implementation practice. Forwarded to EWG via paper issue 2138.