Можно ли определить счетчик в терминах других счетчиков в одном и том же типе перечисления?
Ради любопытства я экспериментирую с этим:
enum RxqType
{
A = (1 << 0),
B = (1 << 1),
C = (A | B),
D = A+B+C
};
Перечисления C и D определены в терминах более ранних счетчиков. Это необычно, поэтому я не уверен, что это безопасно. Я не могу найти никакого примера об этом через Google (возможно, упускаю из вида).
Кажется, все хорошо, когда я printf
или cout
C
и D
на Visual С++ 2013 и MinGW. Но я беспокоюсь, стандартно ли это соответствует, и вызывает ли это поведение undefined.
Может ли кто-нибудь ответить на мое беспокойство по поводу стандартного соответствия и поведения undefined? И есть ли что-нибудь еще, что мне нужно?
Ответы
Ответ 1
enum RxqType
{
A = (1 << 0),
B = (1 << 1),
C = (A | B),
D = A+B+C
};
В C и в С++ это действительно.
Для C:
(C11, 6.2.1p7) "Каждая константа перечисления имеет область действия, которая начинается сразу после появления его определяющего перечислителя в списке перечислителей".
Для С++:
(С++ 11, 3.3.2p4) "Точка объявления для перечислителя сразу же после определения его перечислителя."
Ответ 2
Да, это описано в черновике стандартного раздела C99 6.2.1
Области идентификаторов, которые сообщают нам, что каждый перечислитель находится в области видимости после того, как он определен:
Каждая константа перечисления имеет начинается сразу после появления его определяющего перечислителя в списке перечислителей.
Это описано в стандартном разделе проекта С++ 3.3.2
Точка декларации, в которой говорится:
Точка декларации для перечисления сразу после идентификатора (если есть) в его спецификаторе перечисления (7.2) или его первом opaque-enum-declaration (7.2), в зависимости от того, что наступит раньше.
и для полноты мы можем перейти к разделу 6.7.2.2
Спецификаторы перечисления проекта стандарта C99, в котором говорится, что перечислитель может быть установлен постоянным выражением, а сам перечислитель является постоянным выражением.
enumerator:
enumeration-constant
enumeration-constant = constant-expression
Что такое константное выражение, описано в разделе 6.6
Константные выражения, и это говорит нам, что перечисляющие являются константами, а также что арифметические выражения целочисленных констант также являются постоянными выражениями.
Ответ 3
Хотя, как уже отмечалось, это совершенно верно, есть одна вещь, за которой вы должны обратить внимание: в то время как тип перечисления определяется, в С++, уже заявленные счетчики могут не иметь точного типа, который вы ожидаете, В результате чего-то вроде
enum E {
a = INT_MAX,
b = UINT_MAX,
c = a + 1, // error: overflow
};
недействителен, даже если это:
enum E {
a = INT_MAX,
b = UINT_MAX,
};
enum E2 {
c = a + 1, // okay: a is promoted to unsigned int
};
Для аналогичного примера разрешение перегрузки может не вести себя так, как вы ожидали:
char f(int);
template <typename T>
char (&f(T))[2];
enum E {
a = 0,
b = sizeof(f(a)), // 1
};
enum E2 {
c = sizeof(f(a)), // 2
};
Существуют и другие подобные примеры, которые несколько неточны.
Для C правила немного проще. В C тип константы перечисления не зависит от типа перечисления, поэтому мой пример a + 1
недействителен даже с E2
. Это приводит к постоянным результатам.
Ответ 4
Да, 100% действительны. На самом деле это очень хорошо.
enum RxqType
{
A = (1 << 0),
B = (1 << 1),
C = (A | B),
D = A+B+C
};