2016-12-05 150 views
3

我想要做的是使用枚举来轻松指定不同的绘制模式。到目前为止,这是我得到的:将enum改为下一个值[C++ 11]

class Grid { 
    enum drawMode { GRID, EROSION, RIVERS, HUMIDITY, ATMOSPHERE } 
    drawMode activeDraw; 

    void draw() { 
     switch(activeDraw) { 
     case GRID: 
     drawGrid(); 
     break; 
     case EROSION: 
     drawErosion(); 
     break; 
     // etc.. 
    } 

    void keyPressed(int key) { 
     switch(key) { 
     case ' ': 
     // Cycle activeDraw to next drawMode 
     } 
} 

因此,如果用户点击空格键,activeDraw将从枚举变为下一个值。因此,如果当前的activeDraw是空格后的GRID,它将改变为EROSION,如果activeDraw是ATMOSPHERE,它将改变为GRID。
有没有简单的解决方案呢? 谢谢。

+1

这个问题与C++ 11有关?我建议使用'enum class'将C++ 11限定为这个问题。 – badola

+0

这是相关的,因为在C++ 11中,您必须手动将其转换为整数,这是主要的一点。 –

回答

8

正如人:MarosBeť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 s的很少使用,而有些人认为这是矫枉过正(坏),但它会使你的代码更短(可以说更干净)。

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那么你将不得不static_cast到并从int值中而不是依赖于隐式转换。

+0

我无法在C++中编译'++ activeDraw':错误:'operator ++'(操作数类型为'drawMode')'不匹配,无论是在C++ 11甚至03中。 –

+0

是的,这也是我的问题让。我缺少的是静态强制转换为int并返回,以便+运算符工作如下:activeDraw = static_cast (static_cast (activeDraw)+ 1); –

+0

这应该作为重载'operator ++(drawMode)'和'operator ++(drawMode,int)'来实现。 –

4

由于您的枚举没有强制值,你可以“提高”它们,并在需要时在最后一个项目+ 1进行模复位到第一个:

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

BTW:也能在C语言中有轻微的修改:

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

我认为在C语言中,你根本不需要费心操作 - 'enum'与'int'完全兼容;请纠正我,如果我错了 – anatolyg

+0

@anatolyg你是对的!编辑出来。谢谢 –

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别名类似,我潜入其中。

它使用C++ 11功能,MSVC 2015在悲惨地失败。使用C++ 11编译器来解决这个问题。它可能似乎最初在MSVC 2015中工作,但不要被愚弄。我还没有在MSVC 2017上试过它。