В C ++, в частности в C ++ 14 n4296, есть два параграфа, говорящих о типе перечислителя, что мне кажется противоречивым. См. 7.2 / 5 (то есть 10.2 / 5 в n4659
):
Каждое перечисление определяет тип, который отличается от всех других типов. Каждое перечисление также имеет базовый тип. Базовый тип может быть явно указан с помощью enum-base. Для перечисляемого типа с ограниченным диапазоном базовым типом является int, если он не указан явно. В обоих этих случаях базовый тип считается фиксированным. После закрывающей скобки спецификатора перечисления каждый перечислитель имеет тип своего перечисления. Если базовый тип является фиксированным, типом каждого перечислителя перед закрывающей скобкой является базовый тип и константное выражение в определении перечислителя должно быть преобразованным константным выражением базового типа […]
И 5.1.1 / 11 (то есть 8.1.4.2/4 в n4659
) пишет:
Спецификатор вложенного имени, который обозначает перечисление (7.2), за которым следует имя перечислителя этого перечисления, является квалифицированным идентификатором, который ссылается на перечислитель. Результатом является счетчик. Тип результата — это тип перечисления. Результатом является prvalue.
Затем, что происходит, когда мы обращаемся к перечислителю через nested-name-спецификатор до закрывающей фигурной скобки объявления? Возьмем, к примеру, следующий фрагмент:
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
};
Какой тип выражения E::B
выше? Это противоречие в стандарте? Как gcc, так и clang следует 7.2 / 5.
Я думаю, что стандарт здесь противоречит сам себе, как в 5.1.1 / 11.
Результатом является счетчик. (1)
а также
Тип результата — это тип перечисления. (2)
Если (1) имеет значение true, то тип результата должен быть типом перечислителя, который, согласно 7.2 / 5, является либо базовым типом перечисления, либо типом, определенным перечислением, в зависимости от того, находится ли он до или после закрывающая скобка.
Это означает, что ваш пример кода должен хорошо скомпилироваться, потому что E::B
является B
и тип B
является short
,
Теперь, если вы примете во внимание (2), оно ничего не изменит после закрывающей скобки. Но если (2) верно перед закрывающей скобкой, это означает, что тип E::B
является E
и в то же время тип B
является short
так что вы в конечном итоге E::B != B
что противоречит (1).
Других решений пока нет …