开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜