35

Why do people use enums in C++ as constants when they can use const?

Trott
  • 66,479
  • 23
  • 173
  • 212
Loai Abdelhalim
  • 1,901
  • 4
  • 24
  • 28
  • I know this is a really old thread, but could you give an example? When I read this question I was thinking along the lines of code that returns an int from a function, but uses an enum to define specific 'versions' of the return value, e.g. error condition, timeout condition etc. Some of the answers below seem to address totally different issues to that.In my opinion it's wrong to use an enum in that way unless, as people say, your compiler is limited in its functionality wrt static const. – cosimo193 May 17 '17 at 14:52
  • Possible duplicate of [Should I use #define, enum or const?](https://stackoverflow.com/questions/112433/should-i-use-define-enum-or-const) – phuclv Mar 08 '18 at 09:21

12 Answers12

50

Bruce Eckel gives a reason in 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;
}
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Bastien Léonard
  • 60,478
  • 20
  • 78
  • 95
35

Enums are distinct types, so you can do type-oriented things like overloading with them:

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

void f( Color c ) {
}

void f( Size s ) {
}

int main() {
    f( Red );
    f( Big );
}
Zifre
  • 26,504
  • 11
  • 85
  • 105
  • 9
    This is not what the question asked. The question is: why people write things like: enum {Margin = 50}; – Claudio Oct 16 '13 at 08:37
25

An enumeration implies a set of related constants, so the added information about the relationship must be useful in their model of the problem at hand.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • 37
    Hm, that does not look like an answer to the question (though it was accepted). People use enums where they could use `const` and the values are **not** related. Often you'll see `enum { SOMETHING = 2232; }` (like that; unnamed enum with one value only) instead of `const int SOMETHING = 2232;`. It's because enum never gets any storage while const variable is still a variable and will get (static) storage if the compiler can't proove it won't need one, which it often can't. – Jan Hudec May 12 '11 at 12:09
  • 1
    Another reason is that "const" POD variables are a newer C++ feature, and a lot of older code bases (and programmers who prefer the higher compatibility) still exist. – Jon Watte Nov 21 '16 at 06:13
22

There's a historical reason too when dealing with template metaprogramming. Some compilers could use values from an enum, but not a static const int to instantiate a class.

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

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

Now you can do it the more sensible way:

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

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

Another possible reason, is that a static const int may have memory reserved for it at runtime, whereas an enum is never going to have an actual memory location reserved for it, and will be dealt at compile time. See this related question.

Community
  • 1
  • 1
Eclipse
  • 44,851
  • 20
  • 112
  • 171
10

I like the automatic behavior that can be used with enums, for example:

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

Then it is easy to loop until LAST, and when a new state (or whatever is represented) is added, the logic adapts.

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

Add something...

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

The loop adapts...

FeatureCreep
  • 1,784
  • 1
  • 19
  • 23
  • 1
    Unless someone accidentally adds the new enum literal to the end of the list, or decided to give non-contiguous values to the literals (e.g. enum {} NONE = 0, START = 4, HEY = 7 etc....). – cosimo193 May 17 '17 at 15:28
9

Enums are more descriptive when used. Consider:

int f(int fg, int bg)

versus

 int f(COLOR fg, COLOR bg)

In addition, enums give a bit more type-safety, because

  • integers are not implicitly convertible to enum types
  • enum of one type is not implicitly convertible to enum of another type
ASk
  • 4,157
  • 1
  • 18
  • 15
  • This is an old thread, but the two statements at the end of this answer are false and need correcting. – motiz88 Sep 12 '13 at 11:13
  • 5
    "integers are not implicitly convertible to enum types" and "enum of one type is not implicitly convertible to enum of another type" - false. Plain `enum`s will silently convert to/from integers, in C++ as in C. So they strictly _don't_ provide this safety. However, in C++11, there is `enum class` which is a proper C++ style "re-imagining" of `enum`: The implicit conversions are gone, and additionally value names must always be qualified. This is similar to C# `enum`s, and avoids the name collision / namespace pollution issues that arise with C's old `enum`. – motiz88 Sep 12 '13 at 11:22
  • @motiz88 - I think you may be getting confused on this one. Try this code on gcc (you'll need to reformat it yourself): 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; } Enum values do implicitly convert to integers, but not vice-versa, and "enum types" don't implicitly convert between each other. In principle I believe ASk is correct here, but I don't think it's actually an answer to the op's question! – cosimo193 May 17 '17 at 15:25
5

Before compiler vendors implemented the ISO/IEC 14882:1998 C++ standard, this code to define a constant in a class scope resulted in a compile error:

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

If the constant is an integer type, a kludgy work around is define it in an enum inside the class:

class Foo {
    enum {
        MAX_LEN = 80
    };
    ...
};
Chin Huang
  • 12,912
  • 4
  • 46
  • 47
  • 1
    Non-static constants can't be initialized that way. I believe you meant "static const int Val1". Also, there are drawbacks in using this method of in-class initialization - the symbol for Val1 is not guaranteed to be created. – ASk May 22 '09 at 21:04
  • 1
    @ASk: The problem is the symbol for "static const int Val1" is not guaranteed to **not** be generated, so the programmer uses enum instead, because that does not create symbol at all. – Jan Hudec May 12 '11 at 12:17
4

enums also can be used as a type name. So you can define a function that takes an enum as a parameter, which makes it more clear what kinds of values should be given as arguments to the function, as compared to having the values defined as const variables and the function accepting just "int" as an argument.

Consider:

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
{
   ...
}

versus:

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

void foo (int bar) // what are valid values for bar?
{
   ...
}
Dan Moulding
  • 211,373
  • 23
  • 97
  • 98
  • 1
    `typedef int my_new_fangled_type; void foo(my_new_fangled_type bar);` Problem solved, no enum needed, and I can change the memory representation by replacing `typedef int` with `typedef uchar` or some such. :) – weberc2 Jul 31 '14 at 19:00
2

Some debuggers will show the enumeration name instead of its value when debugging. This can be very helpful. I know that I would rather see day_of_week = MONDAY than day_of_week = 1.

Trent
  • 13,249
  • 4
  • 39
  • 36
2

It's partly because older compilers did not support the declaration of a true class constant

class C
{
  const int ARealConstant = 10;
};

so had to do this

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

For this reason, many portable libraries continue to use this form.

The other reason is that enums can be used as a convenient syntactic device to organise class constants into those that are related, and those that are not

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

vs

class Integer
{
   enum { treatAsNumeric = true };
   enum { treatAsIntegral = true };
   enum { treatAsString = false };
};
DannyT
  • 13,939
  • 1
  • 18
  • 12
0

Using an enum documents the valid choices in a terse manner and allows the compiler to enforce them.

If they are using enum store global constants, like Pi, for example, then I don't know what their goal is.

dss539
  • 6,804
  • 2
  • 34
  • 64
  • 1
    enum is an integral type, I don't believe it can store a constant such as Pi without significant loss of precision :) – ASk May 22 '09 at 21:01
  • they might store 314159 and just div by 10^5 every time :P hopefully the example gives the right idea about what I meant by global constants, however. – dss539 May 22 '09 at 21:16
-1

One reason is that const requires more typing:

enum { Val1, Val2, Val3 };

...versus...

const int Val1=0, Val2=1, Val3=2;
Head Geek
  • 38,128
  • 22
  • 77
  • 87