将枚举更改为下一个值[C ++ 11]

时间:2016-12-05 17:03:42

标签: c++ c++11 enums switch-statement

我想要做的是使用枚举轻松指定不同的绘制模式。到目前为止,这就是我所拥有的:

<GroupBox>
    <ScrollViewer>
        <StackPanel Orientation="Vertical>
              <!-- Place Children Objects here-->
        <StackPanel>
    <ScrollViewer>
<GroupBox>

因此,如果用户点击空格键,activeDraw将从枚举更改为下一个值。因此,如果当前activeDraw在命中空格后为GRID,它将更改为EROSION,如果activeDraw为ATMOSPHERE,则它将更改为GRID。 有一个简单的解决方案吗? 感谢。

4 个答案:

答案 0 :(得分:10)

如MarošBeťko所述,要为变量添加1,您必须将值转换为int并返回:

activeDraw = static_cast<drawMode>(static_cast<int>(activeDraw) + 1);

如果枚举是在没有C ++ 11 enum class语法的情况下定义的(如问题的文本中所示),则不需要转换为int

activeDraw = static_cast<drawMode>(activeDraw + 1);

要使其循环回零,请使用整数运算,模运算符:

activeDraw = static_cast<drawMode>((activeDraw + 1) % (ATMOSPHERE + 1));    

要消除一个丑陋的+1,请在枚举中添加另一个元素:

enum drawMode { ..., ATMOSPHERE, NUM_DRAW_MODES };
...
activeDraw = static_cast<drawMode>((activeDraw + 1) % NUM_DRAW_MODES);

如果您经常使用此代码,也可以将此代码填入operator++

drawMode operator++(drawMode& mode)
{
    mode = static_cast<drawMode>((activeDraw + 1) % NUM_DRAW_MODES);
    return mode;
}

drawMode operator++(drawMode& mode, int) // postfix operator
{
    drawMode result = mode;
    ++mode;
    return result;
}

很少使用enum的重载运算符,有些人认为它有点过分(不好),但它会使你的代码变短(并且可以说更清晰)。

答案 1 :(得分:4)

由于您的枚举没有强制值,您可以“增加”它们,并在最后一项+ 1上执行模数以在需要时重置为第一项:

 activeDraw = drawMode((activeDraw+1) % (ATMOSPHERE+1));

BTW:也可以在C语言中稍作修改:

activeDraw = (activeDraw+1) % (ATMOSPHERE+1);

答案 2 :(得分:1)

这是你应该写一次,使用很多地方。

boost有一些可能有用的运算符库。如果你需要自己编写,这是一个例子:

namespace EnumOps {
  // ADL helper.  See #define below for macro that writes
  // the "this enum should use enum ops" overload:
  template<class T>
  std::false_type use_enum_ops_f(T&&){return {};}

  // trait class that detects if we should be messing with this enum:
  template<class T>
  using use_enum_ops = decltype(use_enum_ops_f( std::declval<T>() ));

  // to-from underlying type:
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  constexpr std::underlying_type_t<E> get_underlying(E e) {
    return static_cast<std::underlying_type_t<E>>(e);
  }
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  constexpr E from_underlying(std::underlying_type_t<E> e) {
    return static_cast<E>(e);
  }

  // Clamps your Enum value from 0 to E::MAX_VALUE using modular arithmetic
  // You must include a MAX_VALUE in your enum.
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E clamp_max( std::underlying_type_t<E> e ) {
    constexpr auto max = get_underlying(E::MAX_VALUE);
    if (e < 0) {
      auto count = -(e-max+1)/max;
      e =  e + count*max;
    }
    return from_underlying<E>(e % max);
  }

  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E& operator+=( E& e, std::underlying_type_t<E> x ) {
    e= clamp_max<E>(get_underlying(e) + x);
    return e;
  }
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E& operator-=( E& e, std::underlying_type_t<E> x ) {
    e= clamp_max<E>(get_underlying(e) - x);
    return e;
  }
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E operator+( E e, std::underlying_type_t<E> x ) {
    return e+=x;
  }
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E operator+( std::underlying_type_t<E> x, E e ) {
    return e+=x;
  }
  // no int - enum permitted, but enum-int is:
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E operator-( E e, std::underlying_type_t<E> x ) {
    e -= x;
    return e;
  }
  // enum-enum returns the distance between them:
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  std::underlying_type_t<E> operator-( E lhs, E rhs ) {
    return get_underlying(lhs) - get_underlying(rhs);
  }
  // ++ and -- support:
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E& operator++( E& lhs ) {
    lhs += 1;
    return lhs;
  }
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E operator++( E& lhs, int ) {
    auto tmp = lhs;
    ++lhs;
    return tmp;
  }
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E& operator--( E& lhs ) {
    lhs -= 1;
    return lhs;
  }
  template<class E,
    std::enable_if_t< use_enum_ops<E>{}, int> =0
  >
  E operator--( E& lhs, int ) {
    auto tmp = lhs;
    --lhs;
    return tmp;
  }
}
// use this macro in the namespace of your enum
// passing it your enun name:
#define ENABLE_ENUM_OPS(...) \
  std::true_type use_enum_ops_f(__VA_ARGS__){return {};}
// Where you wnat to use ops, you must also
// using namespace EnumOps;

使用示例:

namespace somewhere {
  enum class bob { A, B, C, MAX_VALUE };
  ENABLE_ENUM_OPS(bob)
}

int main() {
  using namespace EnumOps;
  auto x = somewhere::bob::A;
  ++x;
  std::cout << (x == somewhere::bob::B) << "\n";
  x+=3;
  std::cout << (x == somewhere::bob::B) << "\n";
  x-=4;
  std::cout << (x == somewhere::bob::A) << "\n";
}

live example

这使用适量的C ++ 14 - std::underlying_type_t<E>。替换为typename std::underlying_type<E>::type。和我偷偷摸摸的任何其他_t别名类似。

它使用MSVC 2015失败的C ++ 11功能。使用C ++ 11编译器来解决该问题。它似乎最初在MSVC 2015中有效,但不要被愚弄。我没有在MSVC 2017上试过它。

答案 3 :(得分:0)

枚举实际上只是命名整数,所以你可以这样对待它们。

如果您在枚举结尾添加NUM_DRAW_MODES值以跟踪计数,那么这应该有效:

void keyPressed(int key) {
  switch(key) {
  case ' ':
    // Cycle activeDraw to next drawMode
    ++activeDraw;
    if (activeDraw >= NUM_DRAW_MODES) {
      activeDraw = GRID;
    }
  }

如果你使用C ++ 11的enum class,那么你必须{int}来自int值而不是依赖于隐式转换。