C++ 为什么可以';I递增枚举类型的变量吗?

C++ 为什么可以';I递增枚举类型的变量吗?,c++,C++,我有一个枚举类型StackID,我使用枚举来引用特定向量的索引,这使我的代码更易于阅读 但是,我现在需要创建一个名为nextAvail的StackID类型的变量。(它实际上是指一个特定的stackID)。我试图增加它,但是在C++中,以下是非法的:< /P> nextAvail++; 这对我来说很有意义。。。因为没有边界检查 我可能忽略了一些显而易见的东西,但什么是好的替代品呢 我还想链接到问题。枚举在语义上应该表示一组不同的相关值 所以你本来可以 enum Colour {RED, GRE

我有一个枚举类型
StackID
,我使用枚举来引用特定向量的索引,这使我的代码更易于阅读

但是,我现在需要创建一个名为
nextAvail
StackID
类型的变量。(它实际上是指一个特定的stackID)。我试图增加它,但是在C++中,以下是非法的:< /P>
nextAvail++;
这对我来说很有意义。。。因为没有边界检查

我可能忽略了一些显而易见的东西,但什么是好的替代品呢



我还想链接到问题。

枚举在语义上应该表示一组不同的相关值

所以你本来可以

enum Colour {RED, GREEN, BLUE};
但这应该相当于:

enum Colour {GREEN, BLUE, RED};
问题是,如果递增枚举,则这些表示形式不同。第一种情况下的GREEN++与第二种情况下的GREEN++不同


使您的程序依赖于enum的声明是灾难维护者的一个秘诀,他们可能会认为enum的顺序无关紧要,从而引入许多无声的bug。

enum将是type
int
,因此您可以强制转换它们。这就是你想做的吗

int ndx = (int) StackID.SomeValue;
...
++ndx;
当然,这会让一些人感到非常困惑


我突然想到,您使用的是
枚举
,您应该在其中使用
常量
,甚至是
#定义
<代码>枚举在具有任意值(精确值没有意义)时最为合适。

int
之间来回转换当然是显而易见的解决方案,然后您清楚地知道,添加发生在
枚举
之外:

nextAvail = static_cast<StackID>(static_cast<int>(nextAvail) + 1);
nextAvail=static_cast(static_cast(nextAvail)+1);

关于oprator++,$5.2.6/1规定:“操作数的类型应为算术类型或指向完整对象类型的指针。”

StackID不符合这里的要求。它是枚举类型

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;
}
一种选择是这样的

$5.7/1-“对于加法,两个操作数都应具有算术或枚举类型,或者一个操作数应为指向完全定义对象类型的指针,另一个操作数应具有整数或枚举类型。”


因为枚举不必是连续的。例如,以这个例子:

enum Colors {
 cRed, // = 0
 cBlue, // = 1
 cGreen = 3
}
在这种情况下会发生什么

Colors color = cBlue;
Colors other = color++;
other应该是
cGreen
还是应该是2。在这种情况下,它不再是有效的枚举成员。这个怎么样

Colors color = cGreen;
Colors other = color++;
other
应该是
cRed
(环绕)还是4

正如您所看到的,能够增加枚举值会带来很多问题,并使它们想要的简单机制复杂化


如果您只关心整数的递增,那么只需将其转换为
int
并递增。

如果要对其执行算术运算,为什么不将
nextAvail
存储为
int

另一个选项是用您自己的类型包装枚举,并为其重载
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;
}
//当心,brain提前编译了代码!
StackID和operator++(StackID和StackID)
{
#如果我的枚举是连续的&&I不担心溢出
返回stackID=static_cast(++static_cast(stackID));
#否则
开关(stackID){
案例值1:返回stackID=value2;
案例值2:返回stackID=value3;
...
案例值n:返回stackID=value1;
}
断言(假);
return stackID;//否则,某些编译器可能会发出警告
#恩迪夫
}
StackID运算符++(StackID和StackID,int)
{
StackID tmp(StackID);
++斯塔基德;
返回tmp;
}

我以这种方式重载了
+/--
运算符:

enum STATE {STATE_1, STATE_2, STATE_3, STATE_4, STATE_5, STATE_6};
//重载STATE++操作符

inline STATE& operator++(STATE& state, int) {
    const int i = static_cast<int>(state)+1;
    state = static_cast<STATE>((i) % 6);
    return state;
}
内联状态和运算符++(状态和状态,int){
const int i=静态(状态)+1;
状态=静态(i)%6);
返回状态;
}
//重载状态-运算符

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;
}
内联状态和运算符--(状态和类型,int){
const int i=静态(类型)-1;
if(i<0){
类型=静态铸件(6);
}否则{
类型=静态浇铸((i)%6);
}
返回类型;
}

<代码> < P> >我很满意这个C++的C++解决方案,用于< <代码> > <代码>循环增加枚举。< /p>
for (Dwg_Version_Type v = R_INVALID; v <= R_AFTER; v++)
用于(Dwg\u版本\u类型v=R\u无效;v

intvi;
对于(图纸版本类型v=R\U无效;

v但是可以明确地将值分配给枚举,例如
enumcolour{RED=0,GREEN=1,BLUE=2}
。在这种情况下,顺序并不重要。是的,但是你超出了枚举应该是什么,并将其作为一组键/值对进行交叉。你说的时候不清楚你在暗示什么“这应该是同等的",您能详细说明一下吗?@BeeBand:更改枚举内的顺序不应该改变代码的行为;但在您的情况下,它会改变。当然。第一个声明表示有三种颜色,即红色、绿色和蓝色。这就是它所说的。但第二个声明也是这样说的。代码的维护者可以完全合理地添加一种颜色,黄色,介于绿色和蓝色之间。但是任何假定(隐式或显式)绿色+1=蓝色的代码都会无声地中断。简言之,枚举用于表示具有公共属性(在本例中,它们是颜色)的值集,而不是它们之间的关系(绿色在蓝色之前,或红色之后等等)嗯。是的,这是我的另一个选择,我只是觉得所有的演员都让代码看起来有点混乱。很明显(对海报来说也是如此)这是非法的,问题是什么是好的替代品如果你超载前缀增量,你也应该总是超载
int vi;
for (Dwg_Version_Type v = R_INVALID; 
     v <= R_AFTER; 
     vi = (int)v, vi++, v = (Dwg_Version_Type)vi)