使用枚举的范围进行简单的状态跟踪

Using ranges of an enum for simple state tracking

我正在使用一系列用于嵌入式系统状态管理的枚举。

我现在正在实现的是一个以简单的方式向用户显示特定模块状态的系统。所以我想将这些不同的状态翻译成 3 个超级状态,在这种情况下 red/yellow/green 表示 error/configuring/running.

到目前为止,我实现它的简单方法如下。

enum State
{
  StateAA = 0,
  StateAB,
  StateAC,
  
  StateBA = 100,
  StateBB,
  StateBC,
  
  StateCA = 200,
  StateCB
};

void DisplayState(State st)
{
    if(st < 100)
        displayColor = red;
    else if(st < 200)
        displayColor = yellow;
    else
        displayColor = green;
}

这允许在不调整显示功能的情况下管理对枚举的更改,只要范围不变即可。

然而,这感觉有点老套,而且为了找到更好的答案,我在措辞上遇到了问题。如有任何建议,我们将不胜感激。

这看起来确实很“hacky”。相反,请考虑使用状态机,其中每个状态依次使用其自己的内部状态机。这个内部状态应该与程序的其余部分无关,而是私有封装的。

还要避免手动为枚举赋值,如果你不这样做,那么你可以使用枚举类型作为数组索引,这很方便。如果你不这样做,你也可以在最后使用 State_n 成员的老派技巧,然后对应于使用的状态数。 (依次可以 static_assert 针对数组等以确保程序完整性。)

我建议在 switch:

中使用“fall-through”案例
enum State
{
  StateAA,
  StateAB,
  StateAC,
  
  StateBA,
  StateBB,
  StateBC,
  
  StateCA,
  StateCB
};

void DisplayState(State st)
{
  switch( st )
  {
      case StateAA :
      case StateAB :
      case StateAC :
      {
         displayColor = red;
      }
      break ;

      case StateBA :
      case StateBB :
      case StateBC :
      {
         displayColor = yellow;
      }
      break ;
  
      case StateCA :
      case StateCB :
      default :
      {
        displayColor = green;
      }
      break ;
   }
}

这样一来,每个案例的枚举就不必是连续的或在特定范围内。

如果您选择不这样做,至少在条件中使用 enum 常量而不是“幻数”:

if(st < StateBA)
    displayColor = red;
else if(st < StateCA)
    displayColor = yellow;
else
    displayColor = green;

或者更好,在枚举中定义组:

enum State
{
  StateAA,
  StateAB,
  StateAC,

  StateB_GroupStart,
  StateBA = StateB_GroupStart,
  StateBB,
  StateBC,

  StateC_GroupStart,
  StateCA = StateC_GroupStart,
  StateCB
};

然后:

if(st < StateB_GroupStart)
    displayColor = red;
else if(st < StateC_GroupStart)
    displayColor = yellow;
else
    displayColor = green;

我真的不能推荐最后两个选项中的任何一个 - 它们只是比您原来的解决方案少了一点“hacky”。他们仍然依赖于 enum 常量的特定顺序,如果您不知道它很重要,这可能很容易在维护中搞砸——它至少需要一个注释来阻止粗心的维护者破坏它。您可以通过定义组结束广告测试在某种程度上缓解这种情况 st 在开始和结束之间,但这只是说明解决方案变得多么笨拙。我还需要一个通常效率较低的 if/else if/else 链。

通过避免在 enum 值中产生“间隙”,以便每个连续值都是连续的,这意味着可以轻松地将开关优化为跳转 -table。如果您在条件测试中使用 enum 常量,则在任何情况下都不需要间隙。