Подтвердить что ты не робот

Можно ли определить счетчик в терминах других счетчиков в одном и том же типе перечисления?

Ради любопытства я экспериментирую с этим:

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? И есть ли что-нибудь еще, что мне нужно?

4b9b3361

Ответ 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
};