ImpalerCore said:
I have two related but separate enumerations where I'd like to use the
same identifier to represent an invalid type.
enum typeA
{
invalid_type = -1,
typeA = 0,
typeB = 1,
...
};
enum type0
{
invalid_type = -1,
type0 = 0,
type1 = 1,
...
};
Is it okay to for these enumerations to share the same identifier as
long as they have the same value in all enumerations that use them?
From my limited experience with the standard, I couldn't pull out
whether this was defined behavior.
It's a constraint violation, assuming both types are declared in the
same scope.
Quoting N1570:
6.7.2.2:
The identifiers in an enumerator list are declared as constants that
have type int and may appear wherever such are permitted.
So your declaration of invalid_type is equivalent to:
const int invalid_type = -1;
A footnote makes it even clearer:
Thus, the identifiers of enumeration constants declared in the same
scope shall all be distinct from each other and from other
identifiers declared in ordinary declarators.
And 6.7p3 says:
If an identifier has no linkage, there shall be no more than one
declaration of the identifier (in a declarator or type specifier)
with the same scope and in the same name space, except that:
[...]
(The exceptions don't apply in this case.)
This is a constraint, so a diagnostic is required. A compiler *could*
issue a warning and accept the declaration anyway, but I don't know of
any that do so.
If you had tried to compile your example, the compiler would have
rejected it; for example, gcc gives me:
c.c:10:18: error: redeclaration of enumerator ‘invalid_type’
c.c:3:18: note: previous definition of ‘invalid_type’ was here
This doesn't prove that it's invalid (it *could* be a compiler bug), but
it's a strong indication.
You could declare the "invalid_type" enumeration constant with a
different name in each enum type, then declare a single:
enum { invalid_type = -1 };
and use that identifier everywhere. Enumeration constants aren't as
strongly associated with their types as you might expect; they're all of
type int, so there's no real type checking. (C++ has different rules,
so if you want your code to be compatible with C++ for some reason
you'll have to be more careful.)