Hello. I was just wondering why people use enums in C++ as constants while they
can use const
.
Thanks
Hello. I was just wondering why people use enums in C++ as constants while they
can use const
.
Thanks
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.
One reason is that const
requires more typing:
enum { Val1, Val2, Val3 };
...versus...
const int Val1=0, Val2=1, Val3=2;
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 );
}
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.
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
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?
{
...
}
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.
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...
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
};
...
};
Bruce Eckel gives a reason in Thinking in C++:
In older versions of C++,
static const
was not supported inside classes. This meant thatconst
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 untaggedenum
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; }
[Edit]
I think it would be more fair to link Bruce Eckel's site: http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html.
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
.
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 };
};