Reputation:
For the sake of curiosity, I am experimenting this:
enum RxqType
{
A = (1 << 0),
B = (1 << 1),
C = (A | B),
D = A+B+C
};
Enumerator C and D are defined in terms of earlier enumerators. It is unusual so I am not sure whether it is safe. I can find no example about it through Google (maybe overlook though).
It seems to be fine when I printf
or cout
C
and D
on Visual C++ 2013 and MinGW. But I am worrying whether it is standard conforming, and whether it triggers undefined behaviours.
Can anyone answer to my worry about standard conformance and undefined behaviour? And is there anything else I have to concern?
Upvotes: 21
Views: 976
Reputation:
Although as noted already, it is perfectly valid, there is one thing you have to look out for: while an enumeration type is being defined, in C++, the already-declared enumerators may not have the exact type you're expecting. As a result, something like
enum E {
a = INT_MAX,
b = UINT_MAX,
c = a + 1, // error: overflow
};
is not valid, even though this is:
enum E {
a = INT_MAX,
b = UINT_MAX,
};
enum E2 {
c = a + 1, // okay: a is promoted to unsigned int
};
For a similar example, overload resolution may not behave like you would expect:
char f(int);
template <typename T>
char (&f(T))[2];
enum E {
a = 0,
b = sizeof(f(a)), // 1
};
enum E2 {
c = sizeof(f(a)), // 2
};
There are other similar examples that are somewhat unintuitive.
For C, the rules are a bit simpler. In C, an enumeration constant's type is independent of the enumeration type, so my example of a + 1
is invalid even with the E2
. This does lead do consistent results.
Upvotes: 1
Reputation: 158619
Yes, this is covered in the draft C99 standard section 6.2.1
Scopes of identifiers which which tells us each enumerator is in scope after it is defined:
Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list.
This is covered in the draft C++ standard section 3.3.2
Point of declaration which says:
The point of declaration for an enumeration is immediately after the identifier (if any) in either its enum-specifier (7.2) or its first opaque-enum-declaration (7.2), whichever comes first.
and for completeness sake we can go to section 6.7.2.2
Enumeration specifiers of the draft C99 standard, which tells us an enumerator can be set by a constant expression and an enumerator itself is a constant expression.
enumerator:
enumeration-constant
enumeration-constant = constant-expression
What are constant expression is covered in section 6.6
Constant expressions and it tells us that enumerators are constants and also that arithmetic expressions of integer constants are also constant expressions.
Upvotes: 5
Reputation: 145899
enum RxqType
{
A = (1 << 0),
B = (1 << 1),
C = (A | B),
D = A+B+C
};
In C and in C++ this is valid.
For C:
(C11, 6.2.1p7) "Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list."
For C++:
(C++11, 3.3.2p4) "The point of declaration for an enumerator is immediately after its enumerator-definition."
Upvotes: 21
Reputation: 7128
Yes, 100% valid. This is just fine, in fact, appreciated.
enum RxqType
{
A = (1 << 0),
B = (1 << 1),
C = (A | B),
D = A+B+C
};
Upvotes: -3