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

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

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

4b9b3361

Ответ 1

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

Ответ 2

Брюс Эккель дает повод в Мышление в С++:

В старых версиях С++ 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;
}

[изменить]

Я думаю, было бы более справедливо связать сайт Брюса Эккела: http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html.

Ответ 3

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

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

void f( Color c ) {
}

void f( Size s ) {
}

int main() {
    f( Red );
    f( Big );
}

Ответ 4

Существует историческая причина также при работе с метапрограммированием шаблонов. Некоторые компиляторы могут использовать значения из перечисления, но не статические константы 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;
};

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

Ответ 5

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

int f(int fg, int bg)

против

 int f(COLOR fg, COLOR bg)

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

  • целые числа неявно конвертируются в типы перечисления
  • перечисление одного типа неявно конвертируется в перечисление другого типа

Ответ 6

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

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

Затем легко зацикливаться до LAST, и когда добавляется новое состояние (или любое другое), логика адаптируется.

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

Добавить что-то...

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

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

Ответ 7

Прежде чем поставщики компиляторов реализовали стандарт ISO/IEC 14882: 1998 С++, этот код для определения константы в области класса привел к ошибке компиляции:

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

Если константа является целым типом, то kludgy work around определяет ее в перечислении внутри класса:

class Foo {
    enum {
        MAX_LEN = 80
    };
    ...
};

Ответ 8

перечисления также могут использоваться как имя типа. Таким образом, вы можете определить функцию, которая принимает enum в качестве параметра, что делает более понятным, какие значения должны указываться в качестве аргументов функции, по сравнению с значениями, определенными как константные переменные, и функцией, принимающей только "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?
{
   ...
}

Ответ 9

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

Ответ 10

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

class C
{
  const int ARealConstant = 10;
};

так должно было это сделать

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

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

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

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

против

class Integer
{
   enum { treatAsNumeric = true };
   enum { treatAsIntegral = true };
   enum { treatAsString = false };
};

Ответ 11

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

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

Ответ 12

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

enum { Val1, Val2, Val3 };

... по сравнению с...

const int Val1=0, Val2=1, Val3=2;