5

Say I have a master enum listing all personnel:

typedef enum all_personnel {
     // male
     TONY,
     MIKE,
     JIM,
     // female
     JESSICA,
     MARY,
} all_personnel_t;

Now I want to define other two enums for male and female (because, for example, some functions only takes males or females enum argument), but I want to use the same name identifiers as in the master enum. Is it possible in C/C++? Or there are other ways?

It seems that the following does not work (compiler complains redeclaration of enumerator ‘TONY’ etc:

typedef enum male_personnel {
    TONY,
    MIKE,
    JIM,
} male_personnel_t;
bruin
  • 979
  • 1
  • 10
  • 30
  • 5
    Do you want to do this in C or C++? – Nicol Bolas May 24 '19 at 04:44
  • 1
    In C, the enumeration constants in any one `enum` type have to be distinct from all other enumeration constants in all other `enum` types in scope — unless you're redefining the types inside a function, which is probably not what you want to do. Enumeration constants are in the [ordinary identifiers](https://port70.net/~nsz/c/c11/n1570.html#6.2.3) name space, along with variable names, type names, function names, etc. – Jonathan Leffler May 24 '19 at 04:52

2 Answers2

6

As mentioned here, you can do this in C++ by using scoped enumerations (C++11) as follows

enum class all_personnel_t { TONY, MARY };
enum class male_personnel_t { TONY };

Or you can put the enums in namespaces as follows

namespace all
{
    enum all_personnel_t { TONY, MARY };
}
namespace male
{
    enum male_personnel_t { TONY };
}
Bhavin
  • 206
  • 2
  • 9
5

C

This is not possible in C because all enumeration constants from the different enumerations that are in scope are part of the same namespace called the ordinary identifiers namespace. So using the same name for the constants will result in a re-declaration error.

As per C11 standard:

6.2.3 Name spaces of identifiers

  1. Thus, there are separate name spaces for various categories of identifiers, as follows:
    ...
    — all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).

C++

This is possible in C++, if you use scoped enumerations.

enum class all_personnel {
     // male
     TONY,
     MIKE,
     JIM,
     // female
     JESSICA,
     MARY,
} ;

enum class male_personnel {
    TONY,
    MIKE,
    JIM,
} ;

However, note that there are no implicit conversions from the values of a scoped enumerator to integral types or from one scoped enumerator to another scoped enumerator. This is because each enumerator becomes a named constant of the enumeration's type.

So the below is not possible:

male_personnel mp2 = all_personnel::TONY; //will not work
all_personnel ap2 = male_personnel::MIKE; //will not work   

and neither is this:

male_personnel mp1 = male_personnel::MIKE; 
all_personnel ap1 = all_personnel::TONY; 
mp1 = ap1; //will not work

See Demo

P.W
  • 26,289
  • 6
  • 39
  • 76
  • Thanks for your answer. Besides no implicit conversion, it seems that it's not enforced that MIKE from two scopes has the same value, unless I explicitly specify the same value `MIKE=0` in multiple places, which is what I want to avoid. My current workaround in C is to prefix a underscore in subset enum identifiers, e.g., `_MIKE = MIKE`. The "cost" is that sometimes I use `MIKE`, and sometimes I use `_MIKE`; – bruin May 24 '19 at 07:33
  • 1
    @bruin: You are welcome. Note that in C, all identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved. So something like `_MIKE` in your code can cause undefined behavior. – P.W May 24 '19 at 07:43
  • Ooops. I was not aware of that. Thanks for pointing that out, I will change the underscore to other characters. – bruin May 24 '19 at 09:40