开发者

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 classes 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 enums 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜