Itamar Katz
Itamar Katz

Reputation: 9645

Do enum values behave like global variables?

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.

Upvotes: 7

Views: 12635

Answers (7)

alexpanter
alexpanter

Reputation: 1578

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
{
    AspectRatio_16_9,  // HD video
    AspectRatio_16_2,  // *for testing purposes*
    AspectRatio_4_3,   // standard monitor
    AspectRatio_3_2,   // classic film
    AspectRatio_21_9,  // cinemascope
    AspectRatio_1_1    // quadratic window
};

It's a type-safe alternative that does not pollute the enclosing scope. It should also be noted that, in order to prevent name clashing with globally defined macros, enum class values should usually not use the ALL_CAPS naming convention.

Upvotes: 1

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145239

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.,

Upvotes: 10

Lockhead
Lockhead

Reputation: 2451

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.

Upvotes: 1

John Dibling
John Dibling

Reputation: 101456

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.

Upvotes: 12

Wyatt Anderson
Wyatt Anderson

Reputation: 9893

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;

Upvotes: 5

user229044
user229044

Reputation: 239260

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

Upvotes: 2

Armen Tsirunyan
Armen Tsirunyan

Reputation: 132984

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

Upvotes: 5

Related Questions