Do enum values behave like global variables?
开发者_StackOverflow社区I have two enums, and if there is one value in one enum with the same name as a value in the other enum:
enum A {joe, bob, doc};
enum B {sunday, monday, doc};
The compiler (Visual Studio's) complains about redefinition of doc
, which implies it treats it as a global variable. Is this so? It is not the behavior I would expect, and it forces me to manage names of all enum elements in my project.
Any insights would help.
It's not treated as a global variable. It's treated as a global identifier.
More precisely, it's treated as an identifier in whatever namespace the enum
is declared in. In your case, that's the global namespace.
For an idea of what the difference is between a global identifier and a global variable, try taking the address of your enum. ;)
Usually when I define enums, I prepend the an abbreviated version of the name of the identifier. Like this:
enum InstrumentType { itStock, itEquityOption, itFutureOption };
This helps to avoid collisions.
Wyatt Anderson has already suggested
namespace A
{
enum A {joe, bob, doc};
}
namespace B
{
enum B {sunday, monday, doc};
}
as a fix for the "enum values are in the same scope as the enum itself" problem, allowing you to write
A::doc;
B::doc;
But this solution is not available when you want an enum
local to a class, at least not without introducing an artificial namespace outside the class.
A simple solution is to instead wrap each enum
in a struct, like so:
struct A
{
enum Enum {joe, bob, doc};
};
struct B
{
enum Enum {sunday, monday, doc};
};
This allows the same usage notation as with the namespace solution,
A::doc;
B::doc;
but it additionally allows
definition within a class,
bringing the enumeration names directly into a class via inheritance, and
local-in-class renaming of the qualifier, via
typedef
.
Plus, the naming convention exemplified above allows
- in my view, a little extra clarity when referring to an enum type, e.g. writing
A::Enum
.
OK, the naming convention can also be used with the namespace based solution…
Cheers & hth.,
Enumerators in C++03 have the same scope as the enumeration .
enum xxx { yyy, zzz };
^ ^ ^
enumeration enumerator enumerator
This is sometimes convenient, sometimes not really.
In C++0x we will have enum class
es which are more like C#'s enums
. In the meantime, just assume (cause that's the language rule) that yyy
and zzz
have exactly the same scope as xxx
If you want them to be global, fix your problem and avoid namespace pollution by throwing your enum
s in a namespace:
namespace A
{
enum A {joe, bob, doc};
}
namespace B
{
enum B {sunday, monday, doc};
}
A::doc;
B::doc;
The values of an enumeration exist in whatever scope the enum
was declared in.
The following works, for example:
enum A {joe, bob, doc};
namespace C { enum B {sunday, monday, doc}; }
or
class A_class { enum A {joe, bob, doc}; };
class B_class { enum B {sunday, monday, doc}; };
The enum's values have the scope of the enum itself, that is, it's declaration scope. For example:
enum A {value = 30};
int main()
{
enum B {value = 32};
int x = value;
}
x will be 32.
Let's say we want to declare aspect ratio for a graphical window. Then defining the enum values as already suggested:
struct __aspect_ratio__
{
enum values
{
ASPECT_RATIO_16_9, // HD video
ASPECT_RATIO_16_2, // *for testing purposes*
ASPECT_RATIO_4_3, // standard monitor
ASPECT_RATIO_3_2, // classic film
ASPECT_RATIO_21_9, // cinemascope
ASPECT_RATIO_1_1 // quadratic window
};
};
typedef __aspect_ratio__::values AspectRatio;
The typedef
in the end allows us to use AspectRatio::ASPECT_RATIO_16_9
as a shorthand for, e.g. function signatures:
void SetAspectRatio(AspectRatio aspect)
{
switch(aspect)
{
case AspectRatio::ASPECT_RATIO_16_9:
// ...
default:
std::cerr << "Undefined aspect ratio enum value!" << std::endl;
}
}
}
This works for me exactly as I would expect it to in C#.
Edit:
Assuming that you are using at least C++11, then you are better off declaring an enum class
:
enum class values
{
ASPECT_RATIO_16_9, // HD video
ASPECT_RATIO_16_2, // *for testing purposes*
ASPECT_RATIO_4_3, // standard monitor
ASPECT_RATIO_3_2, // classic film
ASPECT_RATIO_21_9, // cinemascope
ASPECT_RATIO_1_1 // quadratic window
};
It's a type-safe alternative that does not pollute the enclosing scope.
精彩评论