Почему люди используют перечисления в C ++ как константы, в то время как они могут использовать константу?

Почему люди используют перечисления в C ++ как константы, когда они могут использовать const?


person Loai Nagati    schedule 22.05.2009    source источник
comment
Я знаю, что это действительно старая ветка, но не могли бы вы привести пример? Когда я читал этот вопрос, я думал о строках кода, которые возвращают int из функции, но используют перечисление для определения конкретных «версий» возвращаемого значения, например состояние ошибки, условие тайм-аута и т. д. Некоторые из приведенных ниже ответов, похоже, решают совершенно другие проблемы. На мой взгляд, неправильно использовать перечисление таким образом, если, как говорят люди, ваш компилятор не ограничен в своей функциональности относительно static const.   -  person cosimo193    schedule 17.05.2017
comment
Возможный дубликат Следует использовать #define, enum или const?   -  person phuclv    schedule 08.03.2018


Ответы (12)


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

person duffymo    schedule 22.05.2009
comment
Хм, это не похоже на ответ на вопрос (хотя он был принят). Люди используют перечисления там, где они могут использовать const, а значения не связаны. Часто вы увидите enum { SOMETHING = 2232; } (например, безымянное перечисление только с одним значением) вместо const int SOMETHING = 2232;. Это потому, что enum никогда не получает никакого хранилища, в то время как переменная const по-прежнему является переменной и получит (статическое) хранилище, если компилятор не сможет доказать, что он не понадобится, что часто бывает невозможно. - person Jan Hudec; 12.05.2011
comment
Другая причина заключается в том, что переменные const POD являются новой функцией C ++, и все еще существует множество старых кодовых баз (и программистов, которые предпочитают более высокую совместимость). - person Jon Watte; 21.11.2016

Брюс Экель объясняет причину в Мышлении на C ++:

В более старых версиях C ++ static const не поддерживался внутри классов. Это означало, что const был бесполезен для постоянных выражений внутри классов. Однако люди по-прежнему хотели это сделать, поэтому типичным решением (обычно называемым «enum hack») было использование нетегированного enum без экземпляров. Все значения перечисления должны быть установлены во время компиляции, они являются локальными для класса, а его значения доступны для константных выражений. Таким образом, вы обычно увидите:

#include <iostream>
using namespace std;

class Bunch {
  enum { size = 1000 };
  int i[size];
};

int main() {
  cout << "sizeof(Bunch) = " << sizeof(Bunch) 
       << ", sizeof(i[1000]) = " 
      << sizeof(int[1000]) << endl;
}
person Bastien Léonard    schedule 22.05.2009

Перечисления - это разные типы, поэтому вы можете делать с ними типизированные вещи, например перегрузку:

enum Color { Red,Green,Blue };
enum Size { Big,Little };

void f( Color c ) {
}

void f( Size s ) {
}

int main() {
    f( Red );
    f( Big );
}
person Community    schedule 22.05.2009
comment
Вопрос не в этом. Возникает вопрос: почему люди пишут такие вещи, как: enum {Margin = 50}; - person Claudio; 16.10.2013

Есть и историческая причина, когда дело касается метапрограммирования шаблонов. Некоторые компиляторы могут использовать значения из перечисления, но не статическую const int для создания экземпляра класса.

template <int N>
struct foo
{
    enum { Value = foo<N-1>::Value + N };
};

template <>
struct foo<0>
{
    enum { Value = 0; }
};

Теперь вы можете сделать это более разумным способом:

template <int N>
struct foo
{
    static const int Value = foo<N-1>::Value + N;
};

template <>
struct foo<0>
{
    static const int Value = 0;
};

Другая возможная причина заключается в том, что static const int может иметь память, зарезервированную для нее во время выполнения, тогда как enum никогда не будет иметь фактическую ячейку памяти, зарезервированную для нее, и будет обрабатываться во время компиляции. См. этот связанный вопрос.

person Eclipse    schedule 22.05.2009

При использовании перечисления более информативны. Учитывать:

int f(int fg, int bg)

против

 int f(COLOR fg, COLOR bg)

Кроме того, перечисления обеспечивают немного большую безопасность типов, потому что

  • целые числа не могут быть неявно преобразованы в типы перечисления
  • перечисление одного типа не может быть неявно преобразовано в перечисление другого типа
person ASk    schedule 22.05.2009
comment
Это старый поток, но два утверждения в конце этого ответа неверны и нуждаются в исправлении. - person motiz88; 12.09.2013
comment
целые числа не могут быть неявно преобразованы в типы перечисления, а перечисление одного типа не может быть неявно преобразовано в перечисление другого типа - false. Обычные enums будут незаметно преобразовывать в / из целых чисел в C ++, как и в C. Поэтому они строго не обеспечивают такую ​​безопасность. Однако в C ++ 11 есть enum class, который является правильным переосмыслением стиля C ++ enum: неявные преобразования исчезли, и, кроме того, имена значений всегда должны уточняться. Это похоже на C # enums и позволяет избежать конфликтов имен / проблем загрязнения пространства имен, которые возникают со старым enum C. - person motiz88; 12.09.2013
comment
@ motiz88 - Я думаю, вы можете запутаться в этом. Попробуйте этот код на gcc (вам нужно будет его переформатировать самостоятельно): int main () {enum MyEnum1 {VAL11, VAL12, VAL13}; перечисление MyEnum2 {VAL21, VAL22, VAL23, VAL24}; int int1 = VAL11; MyEnum1 enum1 = 3; MyEnum2 enum2 = VAL11; перечисление2 = перечисление1; int int2 = enum1; возврат 0; } Значения перечислений неявно преобразуются в целые числа, но не наоборот, а типы перечислений не конвертируются между собой неявно. В принципе, я считаю, что ASk здесь правильный, но я не думаю, что на самом деле это ответ на вопрос оператора! - person cosimo193; 17.05.2017

Мне нравится автоматическое поведение, которое можно использовать с перечислениями, например:

enum {NONE, START, HEY, HO, LAST};

Затем легко выполнить цикл до ПОСЛЕДНЕГО, и когда добавляется новое состояние (или что-то еще, что представлено), логика адаптируется.

for (int i = NONE; i < LAST; i++)
{
    // Do stuff...
}

Добавьте что-нибудь...

enum {NONE, START, HEY, WEE, HO, LAST};

Петля адаптируется ...

person FeatureCreep    schedule 22.05.2009
comment
Если только кто-то случайно не добавит новый литерал enum в конец списка или не решил присвоить литералам несмежные значения (например, enum {} NONE = 0, START = 4, HEY = 7 и т. Д. ...). - person cosimo193; 17.05.2017

До того, как поставщики компиляторов внедрили стандарт ISO / IEC 14882: 1998 C ++, этот код для определения константы в области класса приводил к ошибке компиляции:

class Foo {
    static const int MAX_LEN = 80;
    ...
};

Если константа является целочисленным типом, непростая задача - определить ее в перечислении внутри класса:

class Foo {
    enum {
        MAX_LEN = 80
    };
    ...
};
person Chin Huang    schedule 22.05.2009
comment
Таким образом нельзя инициализировать нестатические константы. Я полагаю, вы имели в виду static const int Val1. Также есть недостатки в использовании этого метода инициализации класса - не гарантируется создание символа для Val1. - person ASk; 23.05.2009
comment
@ASk: Проблема в том, что символ для static const int Val1 не гарантированно не будет сгенерирован, поэтому вместо этого программист использует enum, потому что он вообще не создает символ. - person Jan Hudec; 12.05.2011

перечисления также могут использоваться как имя типа. Таким образом, вы можете определить функцию, которая принимает перечисление в качестве параметра, что делает более ясным, какие типы значений должны быть указаны в качестве аргументов функции, по сравнению со значениями, определенными как константные переменные, и функцией, принимающей только "int" как аргумент.

Учитывать:

enum my_new_fangled_type {
  baz = 0,
  meh = 1
};

void foo (my_new_fangled_type bar) // bar can be a value listed in the enum
{
   ...
}

против:

int const baz = 0;
int const meh = 1;

void foo (int bar) // what are valid values for bar?
{
   ...
}
person Dan Moulding    schedule 22.05.2009
comment
typedef int my_new_fangled_type; void foo(my_new_fangled_type bar); Проблема решена, перечисление не требуется, и я могу изменить представление памяти, заменив typedef int на typedef uchar или что-то подобное. :) - person weberc2; 31.07.2014

Некоторые отладчики будут отображать имя перечисления вместо его значения при отладке. Это может быть очень полезно. Я знаю, что предпочитаю видеть day_of_week = MONDAY, чем day_of_week = 1.

person Trent    schedule 22.05.2009

Отчасти потому, что старые компиляторы не поддерживали объявление истинной константы класса.

class C
{
  const int ARealConstant = 10;
};

так что пришлось сделать это

class C
{
  enum { ARealConstant = 10 };
};

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

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

class DirectorySearcher
{
  enum options
  {
    showFiles = 0x01,
    showDirectories = 0x02,
    showLinks = 0x04,
  };
};

vs

class Integer
{
   enum { treatAsNumeric = true };
   enum { treatAsIntegral = true };
   enum { treatAsString = false };
};
person DannyT    schedule 22.05.2009

Использование перечисления кратко документирует допустимые варианты и позволяет компилятору применять их.

Если они используют глобальные константы enum store, например, Pi, то я не знаю, какова их цель.

person dss539    schedule 22.05.2009
comment
enum - это целочисленный тип, я не верю, что он может хранить константу, такую ​​как Pi, без значительной потери точности :) - person ASk; 23.05.2009
comment
они могут хранить 314159 и каждый раз просто div на 10 ^ 5: P, надеюсь, этот пример дает правильное представление о том, что я имел в виду под глобальными константами. - person dss539; 23.05.2009

Одна из причин заключается в том, что const требует большего набора текста:

enum { Val1, Val2, Val3 };

...против...

const int Val1=0, Val2=1, Val3=2;
person Head Geek    schedule 22.05.2009
comment
Это не единственная причина. Кроме того, нет большой разницы в наборе текста. - person Loai Nagati; 23.05.2009