Why can't I increment a variable of an enumerated type?
I have a enumerated type StackID
, and I am using the enumeration to refer to an index of a particular vector and it makes my code easier to read.
However, I now have the need to create a variable called nextAvail
of type StackID
. (it actually refers to a particular stackID ). I tried to increment it but in C++, the following is illegal:
nextAvail++;
Which sort of makes sense to me ... because there's no bounds checking.
I'm probably overlooking something obvious, but what's a good substitute?
I also want to link to开发者_如何学Go this question.
I'm probably overlooking something obvious, but what's a good substitute?
Overloading operator++
:
// Beware, brain-compiled code ahead!
StackID& operator++(StackID& stackID)
{
#if MY_ENUMS_ARE_CONTIGUOUS && I_DO_NOT_WORRY_ABOUT_OVERFLOW
return stackID = static_cast<StackID>( ++static_cast<int>(stackID) );
#else
switch(stackID) {
case value1 : return stackID = value2;
case value2 : return stackID = value3;
...
case valueN : return stackID = value1;
}
assert(false);
return stackID; // some compilers might warn otherwise
#endif
}
StackID operator++(StackID& stackID, int)
{
StackID tmp(stackID);
++stackID;
return tmp;
}
Because enumerations do not have to be contiguous. E.g. take this example:
enum Colors {
cRed, // = 0
cBlue, // = 1
cGreen = 3
}
What should happen in this scenario?
Colors color = cBlue;
Colors other = color++;
Should other be cGreen
or should it be 2. In that case it's not a valid enumeration member anymore. What about this?
Colors color = cGreen;
Colors other = color++;
Should other
be cRed
(wrap around) or 4?
As you can see, being able to increment enumeration values introduces a whole lot of questions and complicates the simple mechanism that they intend to be.
If all you care about is the integer value being incremented, then simply cast to int
and increment that.
Casting back and forth to/from int
is of course the obvious solution, then you make clear that you understand that the addition is happening "outside" the enum
:
nextAvail = static_cast<StackID>(static_cast<int>(nextAvail) + 1);
Why not store nextAvail
as an int
instead if you're going to do arithmetic operations on it?
Another option would be to wrap the enum in your own type and overload operator ++
for it (which also could wrap around or something for instance).
An enumeration is semantically supposed to represent a set of distinct related, values.
So you could have
enum Colour {RED, GREEN, BLUE};
But that should be equivalent to:
enum Colour {GREEN, BLUE, RED};
The problem is that if you increment an enum then those representations are not the same. GREEN++ in the first case is not the same as GREEN++ in the second.
Making your program dependent on the declaration of the enum is a recipe for disaster - maintainers may assume that the order of the enum doesnt matter, introducing many silent bugs.
Very Simple:
nextAvail = (StackID)(nextAvail + 1);
Enums are going to be type int
, so you can cast them. Is this what you're trying to do?
int ndx = (int) StackID.SomeValue;
...
++ndx;
This is going to make someone very confused down the line, of course.
It occurs to me that you're using an enum
where you should be using const
, or even #define
. enum
is most appropriate when you have arbitrary values (where the exact value is not meaningful).
I've overloaded the ++/--
operator in this way:
enum STATE {STATE_1, STATE_2, STATE_3, STATE_4, STATE_5, STATE_6};
// Overload the STATE++ operator
inline STATE& operator++(STATE& state, int) {
const int i = static_cast<int>(state)+1;
state = static_cast<STATE>((i) % 6);
return state;
}
// Overload the STATE-- operator
inline STATE& operator--(STATE& type, int) {
const int i = static_cast<int>(type)-1;
if (i < 0) {
type = static_cast<STATE>(6);
} else {
type = static_cast<STATE>((i) % 6);
}
return type;
}
With respect to oprator++, $5.2.6/1 states- "The type of the operand shall be an arithmetic type or a pointer to a complete object type."
StackID does not fit the bill here. It is of enumeration type.
One option is like this
$5.7/1 - "For addition, either both operands shall have arithmetic or enumeration type, or one operand shall be a pointer to a completely defined object type and the other shall have integral or enumeration type."
enum Possibility {Yes, No, Maybe};
Possibility operator++(Possibility const& r){
return Possibility(r + 1); // convert r to integer, add 1, convert back to Enum
}
int main(){
Possibility p = Yes;
Possibility p1 = ++p;
}
I'm quite happy with this C plus C++ solution for a for
loop incrementing an enum.
for (Dwg_Version_Type v = R_INVALID; v <= R_AFTER; v++)
=>
int vi;
for (Dwg_Version_Type v = R_INVALID;
v <= R_AFTER;
vi = (int)v, vi++, v = (Dwg_Version_Type)vi)
The other solutions here are not C backcompat, and quite large.
精彩评论