2009-05-22 3 views
31

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

+0

Я знаю, что это это действительно старая нить, но вы могли бы привести пример? Когда я прочитал этот вопрос, я думал о строках кода, который возвращает int из функции, но использует перечисление для определения конкретных «версий» возвращаемого значения, например. условие ошибки, время ожидания и т. д. Некоторые из приведенных ниже ответов, похоже, затрагивают совершенно разные проблемы. На мой взгляд, неправильно использовать перечисление таким образом, если, как говорят люди, ваш компилятор ограничен в своих функциях по static const. – cosimo193

+0

Возможный дубликат [Должен ли я использовать #define, enum или const?] (Https://stackoverflow.com/questions/112433/should-i-use-define-enum-or-const) –

ответ

20

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

+30

Хм, это не выглядит как ответ на вопрос (хотя он был принят). Люди используют перечисления, где они могут использовать 'const', а значения ** не связаны **. Часто вы увидите 'enum {SOMETHING = 2232; } '(например, unnamed enum только с одним значением) вместо' const int SOMETHING = 2232; '.Это потому, что перечисление никогда не получает никакого хранилища, в то время как переменная const по-прежнему является переменной и будет получать (статическое) хранилище, если компилятор не может его использовать, он не понадобится, что часто не может. –

+0

Другая причина в том, что переменные P const «const» являются более новой функцией C++, и многие старые кодовые базы (и программисты, которые предпочитают более высокую совместимость) все еще существуют. –

-1

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

enum { Val1, Val2, Val3 }; 

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

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

Это не единственная причина. Кроме того, нет большой разницы при наборе текста. –

34

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

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

void f(Color c) { 
} 

void f(Size s) { 
} 

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

Это не вопрос. Вопрос в том, почему люди пишут такие вещи, как: enum {Margin = 50}; – Claudio

20

Существует историческая причина также при рассмотрении шаблона aprogramming. Некоторые компиляторы могут использовать значения из перечисления, но не статические константы 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 может иметь память, зарезервированный для него во время выполнения, в то время как перечисление никогда не будет имеют фактическое место памяти, зарезервированное для него, и будут обрабатываться во время компиляции. См. this related question.

10

Указанные значения являются более наглядными. Рассмотрим:

int f(int fg, int bg) 

против

int f(COLOR fg, COLOR bg) 

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

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

Это старый поток, но два утверждения в конце этого ответа ложны и нуждаются в исправлении. – motiz88

+4

«целые числа неявно конвертируются в типы перечислений», а «перечисление одного типа неявно конвертируется в перечисление другого типа» - false. Plain 'enum' будет молча преобразовывать в/из целых чисел, в C++, как в C. Таким образом, они строго не обеспечивают эту безопасность. Однако в C++ 11 существует 'enum class', который является правильным стилем C++« re-imagining »из' enum': неявные преобразования исчезли, и дополнительные имена значений всегда должны быть квалифицированы. Это похоже на C# 'enum' и позволяет избежать проблем с загрязнением имен/пространства имен, возникающих с помощью старого 'enum' C. – motiz88

+0

@ motiz88 - Я думаю, вы можете запутаться в этом. Попробуйте этот код на gcc (вам нужно будет переформатировать его самостоятельно): int main() {enum MyEnum1 {VAL11, VAL12, VAL13}; enum MyEnum2 {VAL21, VAL22, VAL23, VAL24}; int int1 = VAL11; MyEnum1 enum1 = 3; MyEnum2 enum2 = VAL11; enum2 = enum1; int int2 = enum1; return 0; } Значения перечисления неявно преобразуются в целые числа, но не наоборот, а «типы перечислений» неявно конвертируются между собой. В принципе, я считаю, что ASk здесь верен, но я не думаю, что это на самом деле ответ на вопрос о! – cosimo193

4

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

'typedef int my_new_fangled_type; void foo (my_new_fangled_type bar); 'Задача решена, не требуется перечисление, и я могу изменить представление памяти, заменив typedef int на' typedef uchar' или некоторые из них. :) – weberc2

0

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

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

+1

enum является интегральным типом, я не верю, что он может хранить постоянную, такую ​​как Pi, без значительной потери точности :) – ASk

+0

они могут хранить 314159 и просто делить на 10^5 каждый раз: P надеюсь, что пример дает Однако правильная идея о том, что я имел в виду под глобальными константами. – dss539

10

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

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

Тогда легко в цикле до последнего, а когда новое состояние (или любой другой представлен) добавлен, логика адаптируется.

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

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

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

Петля приспосабливается ...

+0

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

5

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

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

Если константа является целым типом, то kludgy работает вокруг d efine его в перечислении внутри класса:

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

Нестатические константы не могут быть инициализированы таким образом. Я полагаю, вы имели в виду «static const int Val1». Кроме того, существуют недостатки в использовании этого метода инициализации в классе - символ Val1 не гарантируется. – ASk

+0

@ASk: Проблема заключается в том, что символ «static const int Val1» не гарантирован ** не генерируется **, поэтому программист использует вместо него перечисление, потому что это вообще не создает символ. –

41

Брюс Eckel дает основание в Thinking in C++:

In older versions of C++, static const was not supported inside classes. This meant that const was useless for constant expressions inside classes. However, people still wanted to do this so a typical solution (usually referred to as the “enum hack”) was to use an untagged enum with no instances. An enumeration must have all its values established at compile time, it’s local to the class, and its values are available for constant expressions. Thus, you will commonly see:

#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; 
} 

[Редактировать]

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

2

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

2

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

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 }; 
};