Что означает «статическое перечисление» в C ++? - PullRequest
32 голосов
/ 11 февраля 2011

Я недавно сталкивался с этим:

static enum Response{
    NO_ERROR=0,
    MISSING_DESCRIPTOR,
    ...
};

Он компилируется и работает под Microsoft VS2005.Однако я не уверен, что должен делать модификатор static.Отличается ли это от следующего?

enum Response {
    NO_ERROR=0,
    MISSING_DESCRIPTOR,
    ...
};

Ответы [ 6 ]

57 голосов
/ 11 февраля 2011

Этот точный код, только с удаленным многоточием, не является допустимым C ++. Вы не можете использовать спецификатор класса хранения static в объявлении enum; в этом нет никакого смысла (только объекты, функции и анонимные объединения могут быть объявлены static).

Однако вы можете объявить enum и переменную в одном объявлении:

static enum Response {
    NO_ERROR = 0,
    MISSING_DESCRIPTOR
} x; 

static здесь относится к x, и оно фактически такое же, как если бы вы сказали:

enum Response { 
    NO_ERROR = 0,
    MISSING_DESCRIPTOR
};

static Response x;
14 голосов
/ 11 февраля 2011

Удивительно, но вы можете поместить туда другие decl-спецификаторы .
Это прекрасно компилируется в VS2008:

auto const enum TestEnum {
    Why,
    Does
};

register volatile enum TestEnum2 {
    This,
    Work
};

Но это не имеет никакого смысла:)

Я подозреваю, что проблема здесь заключается в разборе, потому что код, подобный этому:

enum TestEnum3 { Hello, World };  // Define enum
enum TestEnum3 x = World;         // Use enum

Может также быть записан как:

enum TestEnum3 { Hello, World } x = World; // Define and use enum.

Интересно, я замечаю, если вы делаетеэто в VS2008:

enum TestEnum3 { Hello, World };
const enum TestEnum3 e3 = World;
const enum TestEnum4 { F, M, L } e4 = F;

e3 = Hello; // error C2166: l-value specifies const object (Good!)
e4 = M;     // NO ERROR here though - why?

Таким образом, они не эквивалентны, как в случае TestEnum4, который, кажется, отбрасывает спецификатор decl const .Все очень странно.

7 голосов
/ 11 февраля 2011
static enum Response { /*... */ };

Вы не можете определить static enum в C ++. static может быть только переменной перечисления, но не типом самой!

Компилируя ваш код с GCC версия 4.3.4, выдает эту ошибку:

prog.cpp: 7: ошибка: класс хранилища может указывать только для объектов и Функции

Посмотрите на себя в Интернете на ideone: http://www.ideone.com/cI1bt

Я думаю, этим все сказано.

-

Однако, если вы хотите ограничить тип enum Response в его собственной единице перевода, тогда вы можете использовать безымянное пространство имен. Посмотрите на эту тему:

Превосходство безымянного пространства имен над статическим?

2 голосов

Стандарт

В проекте стандарта C ++ 11 N3337 Приложение C 7.1.1 говорится, что он был разрешен в C, но не имел никакого эффекта и стал незаконным в C ++:

Изменение: в C ++ статические или внешние указатели могут применяться только к именам объектов или функций. Использование этих спецификаторов с объявлениями типов недопустимо в C ++. В C эти спецификаторы игнорируются при использовании на объявлениях типа. Пример:

static struct S {    // valid C, invalid in C++
  int i;
};

Обоснование: спецификаторы класса хранения не имеют никакого смысла, когда связаны с типом. В C ++, класс члены могут быть объявлены со спецификатором класса статического хранилища. Разрешение спецификаторов класса хранения по типу объявления могут сделать код запутанным для пользователей.

И как struct, enum также является объявлением типа.

Обоснование реализации

Определения Enum не имеют хранения и не генерируют символы в объектных файлах, таких как переменные и функции. Просто попробуйте скомпилировать и декомпилировать:

struct S { int i; int j; };
int i;

с:

g++ -c main.c
nm main.o

и вы увидите, что нет символа S, но есть символ i.

Когда компилятор видит значения перечисления, он просто вставляет их буквально в скомпилированный код. Конечно, это работает только потому, что они являются константами времени компиляции.

Поэтому они должны быть включены в заголовочные файлы.

Смотри также:

1 голос
/ 11 марта 2012

В C #:

';' необязательно для обратной совместимости после блока enum. Он не допускает такую ​​семантику в этом языке для именованных типов. статические, публичные и т. д. имеют особое внимание. Пространство имен не может содержать элементы, такие как поля или методы.

Требуется тег:

ArgTypes var = ArgTypes.CUT;

В C / C ++:

Требуется ';' в конце блока enum. Для глобальных переменных пространства имен, перечислений и т. Д. static по умолчанию.

int type;

typedef enum {
  TOKENIZE,
  CUT
} ArgTypes;
type = TOKENIZE;  /* <ArgTypes>::TOKENIZE */
type = ArgTypes::CUT;

// Recommended Use
enum ArgTypes {
  TOKENIZE,
  CUT
};  /* Same as above */

enum Test {
  TOKENIZE,
  CUT
} ArgTypes;
type = ArgTypes::TOKENIZE;
type = CUT;   /* Assign type =>  <Test>.CUT */
type = Test::CUT;

enum {
  TOKENIZE,
  CUT
} ArgTypes;  /* Unamed.. requires tag */
type = TOKENIZE; /* <unamed>.TOKENIZE=0 => #define TOKENIZE 0*/
type = ArgTypes::TOKENIZE;  /* ** ERROR ** */
0 голосов
/ 11 февраля 2011

Я не уверен, почему использовался static или почему он даже компилируется. Должен быть просто enum Response. Перечислители не являются статическими данными.

...