39

I have two enums in my code:

enum Month {January, February, March, April, May, June, July,
        August, September, October, November, December};
enum ShortMonth {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};

May is a common element in both enums, so the compiler says:

Redeclaration of enumerator 'May'.

Why does it say so? And how can I circumvent this?

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Pieter
  • 31,619
  • 76
  • 167
  • 242

8 Answers8

49

Enum names are in global scope, they need to be unique. Remember that you don't need to qualify the enum symbols with the enum name, you do just:

Month xmas = December;

not:

Month xmas = Month.December;  /* This is not C. */

For this reason, you often see people prefixing the symbol names with the enum's name:

enum Month { Month_January, Month_February, /* and so on */ };
unwind
  • 391,730
  • 64
  • 469
  • 606
  • still, is there a scenario where the two names could conflict? Like, can they be assigned to or compared with enum of their own type? Or is it just compiler writers being protective (or lazy)? – SF. Jan 29 '10 at 12:49
  • To have both definitions possible, you'd need overloading resolution taking into account the context of use. There is no (user level) overloading in C. And in C++, overloading resolution doesn't take the context of use into account (excepted for implicit conversion) – AProgrammer Jan 29 '10 at 12:54
  • 2
    @SF: Imagine two enums: `Colors` and `Fruits`. What would be the value of `Orange`? – mouviciel Jan 29 '10 at 12:55
  • 1
    An enum has int type in C, it's not a separate type. Some compilers will warn if you compare it with other enums though. – nos Jan 29 '10 at 12:56
  • 1
    @nos "enum has int type" Hmmm, I thought `enum` could have various types: [Ref](http://stackoverflow.com/a/3509650/2410359). – chux - Reinstate Monica Apr 13 '15 at 16:58
32

I suggest you merge the two:

enum Month {
  Jan, January=Jan, Feb, February=Feb, Mar, March=Mar, 
  Apr, April=Apr,   May,               Jun, June=Jun, 
  Jul, July=Jul,    Aug, August=Aug,   Sep, September=Sep, 
  Oct, October=Oct, Nov, November=Nov, Dec, December=Dec};

Which will have exactly the same effect, and is more convenient.

If you want January to have the value 1, instead of 0, add this:

enum Month {
  Jan=1, January=Jan, Feb, February=Feb, ....
Alex Brown
  • 41,819
  • 10
  • 94
  • 108
13

In C++, to avoid name clashing you could wrap your enums into structs:

struct Month { enum {January, February, March, April, May, June, July,
        August, September, October, November, December}; };
struct ShortMonth { enum {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; };
Alexander Poluektov
  • 7,844
  • 1
  • 28
  • 32
9

In C++11 you can use scoped enumerations to fix this this. This will remove the names from the global scope and scope them to the enum name.

enum class Identity
{
       UNKNOWN = 1,
       CHECKED = 2,
       UNCHECKED =3
};

enum class Status
{
       UNKNOWN = 0,
       PENDING = 1,
       APPROVED = 2,
       UNAPPROVED =3
};

int main ()
{
    Identity::UNKNOWN;
    Status::UNKNOW;
}

Live Example

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
7

What unwind said. But I'd also like to say that your example seems like a pretty unusual use of enums. I can't see the value of having a ShortMonth and a LongMonth both referring to the same thing - this would make sense for strings, but not for enums. Why not just have a single Month enum type?

3

My suggestion here is to have just one enum, as they are the same type. If you want short aliases to type less in your code (even if I wouldn't advise you to do so), you can do:

enum Month {
 January, Jan = January,
 February, Feb = February,
 March, Mar = March,
 April, Apr = April
 May,
 June, Jun = June,
 July, Jul = July,
 ...};

And to have different presentation names (short and long), you should have two distinct string arrays that are indexed by the enum.

char[MAX_MONTH_NAME_LENGTH][12] month_long_names = {
  "January", "February", ...
}

char[3][12] short_long_names = {
  "Jan", "Feb", ...
}

printf("month %d long name is %s, and short name is %s\n", May, long_month_names[May], short_month_names[May]);
fortran
  • 74,053
  • 25
  • 135
  • 175
1

In C enums are used without any type prefix, so you write:

month[0] = January;  
month[4] = May;

The enum Month and ShortMonth have the same scope so the compiler can't know which May to use. An obvious fix would be to prefix the enums but i'm not sure that your use of these enums in this case is warranted.

-4
typedef enum {Jan, January, Feb, February, Mar, March, Apr, April, May, Jun, June, Jul, July,
    Aug, August, Sep, September, Oct, October, Nov, November, Dec, December} Month,ShortMonth;

Merge them become one

cocoa
  • 11
  • 6