Почему вы используете typedef при объявлении перечисления на С++?

Я не писал ни одного С++ годами, и теперь я пытаюсь вернуться к нему. Затем я столкнулся с этим и подумал о том, чтобы отказаться:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Что это? Почему ключевое слово typedef используется здесь? Почему имя TokenType появляется в этом объявлении дважды? Чем отличается семантика от этого:

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};

Ответ 1

В C, объявив ваш enum, первый способ позволяет вам использовать его так:

TokenType my_type;

Если вы используете второй стиль, вам придется объявить свою переменную следующим образом:

enum TokenType my_type;

Как уже упоминалось другими, это не влияет на С++. Я предполагаю, что либо человек, который написал это, программист C в глубине души, либо вы компилируете C-код как С++. В любом случае, это не повлияет на поведение вашего кода.

Ответ 2

Это наследие C, на C, если вы это сделаете:

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

вам нужно будет использовать его, например:

enum TokenType foo;

Но если вы это сделаете:

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Вы сможете объявить:

TokenType foo;

Но в С++ вы можете использовать только прежнее определение и использовать его так, как если бы он был в C typedef.

Ответ 3

Вам не нужно это делать. В C (не С++) вам нужно было использовать enum Enumname для ссылки на элемент данных перечисляемого типа. Чтобы упростить его, вам было разрешено вводить его в один тип данных имени.

typedef enum MyEnum { 
  //...
} MyEnum;

разрешенные функции, принимающие параметр перечисления, определяемый как

void f( MyEnum x )

вместо более длинного

void f( enum MyEnum x )

Обратите внимание, что имя имени типа не обязательно должно совпадать с именем перечисления. То же самое происходит с structs.

В С++, с другой стороны, это не требуется, так как перечисления, классы и структуры могут быть доступны непосредственно как типы по их именам.

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C

Ответ 4

В C это хороший стиль, потому что вы можете изменить тип на что-то помимо перечисления.

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

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

Ответ 5

Задержка с C.

Ответ 6

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

Ответ 7

Некоторые говорят, что у C нет пространств имен, но это неверно. Он имеет три:

  • enum
  • struct
  • Глобальный (все остальное)

typedef enum { } XYZ; объявляет анонимное перечисление и импортирует его в глобальное пространство имен с глобальным именем XYZ.

typedef enum ABC { } XYZ; объявляет перечисление с именем ABC в пространстве имен enum, затем импортирует его в глобальное пространство имен как XYZ.

enum XYZ x; объявляет переменную типа XYZ в пространстве имен enum.

То же самое и для пространства имен struct.

Некоторые люди не хотят беспокоиться об отдельных пространствах имен, чтобы они набирали все. Другие никогда не печатаются, потому что им требуется пространство имен.

Ответ 8

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

Здесь это. Я должен процитировать объяснение, которое всегда на уме, когда я должен схватить некоторые неприятные typedefs:

В объявлениях переменных введенные имена являются экземплярами соответствующих типов. [...] Однако, когда ключевое слово typedef предшествует объявлению, введенные имена являются псевдонимами соответствующих типов

Как уже говорилось ранее, нет необходимости использовать typedefs, объявляющие перечисления в С++. Но это объяснение синтаксиса typedef! Я надеюсь, что это поможет (возможно, не OP, поскольку это было почти 10 лет, но каждый, кто пытается понять такие вещи).

Ответ 9

В некотором руководстве C codestyle версия typedef считается предпочтительной для "ясности" и "простоты". Я не согласен, потому что typedef запутывает реальную природу объявленного объекта. На самом деле, я не использую typedefs, потому что, объявляя переменную C, я хочу быть уверенным в том, что на самом деле является объектом. Этот выбор помогает мне быстрее запоминать то, что на самом деле делает старый кусок кода, и поможет другим при сохранении кода в будущем.