Почему люди используют перечисления в С++ в качестве констант, когда они могут использовать const?
Почему люди используют перечисления в С++ как константы, в то время как они могут использовать const?
Ответ 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;