Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type of an enumerator in the declaration of its enum

In C++, specifically in C++14 n4296, there are two paragraps talking about type of an enumerator, which seem to be contradictory to me. See 7.2/5 (which is 10.2/5 in n4659):

Each enumeration defines a type that is different from all other types. Each enumeration also has an underlying type. The underlying type can be explicitly specified using an enum-base. For a scoped enumeration type, the underlying type is int if it is not explicitly specified. In both of these cases, the underlying type is said to be fixed. Following the closing brace of an enum-specifier, each enumerator has the type of its enumeration. If the underlying type is fixed, the type of each enumerator prior to the closing brace is the underlying type and the constant-expression in the enumerator-definition shall be a converted constant expression of the underlying type [...]

And 5.1.1/11 (which is 8.1.4.2/4 in n4659) writes:

A nested-name-specifier that denotes an enumeration (7.2), followed by the name of an enumerator of that enumeration, is a qualified-id that refers to the enumerator. The result is the enumerator. The type of the result is the type of the enumeration. The result is a prvalue.

Then, what happens when we refer to an enumerator through nested-name-specifier prior to closing brace of the declaration? Take for example the following snippet:

template < typename T1, typename T2 >
struct fail_if_not_same {
    static_assert(std::is_same<T1, T2>::value, "Fail!");
    static constexpr int value = 0;
};

enum class E : short {
    A,
    B = A + 1,
    C = fail_if_not_same<decltype(B), short>::value,
    D = fail_if_not_same<decltype(E::B), short>::value
};

What is the type of the expression E::B above? Is this a contradiction in standard? Both gcc and clang follows the 7.2/5.

like image 505
Jan Tušil Avatar asked Feb 21 '17 13:02

Jan Tušil


1 Answers

I think the standard contradicts itself here as you have in 5.1.1/11

The result is the enumerator. (1)

and

The type of the result is the type of the enumeration. (2)

If (1) is true, then the result type shall be the type of the enumerator, which, according to 7.2/5, is either the underlying type of the enumeration or the type defined by the enumeration depending if it is before or after the closing brace.

Meaning that your code sample should compile fine because E::B is B and the type of B is short.

Now if you take (2) into account, it does not change anything after the closing brace. But if (2) is true before the closing brace, it means that the type of E::B is E and at the same time the type of B is short, so you end up with E::B != B which contradicts (1).

like image 196
Benjamin T Avatar answered Nov 01 '22 09:11

Benjamin T