在相关讨论之后枚举类"的递增和递减 ,我想问一下enum class类型的算术运算符的可能实现.
Following the discussion in question Incrementation and decrementation of "enum class", I'd like to ask about the possible implementation of arithmetic operators for enum class types.
原始问题的示例:
enum class Colors { Black, Blue, White, END_OF_LIST }; // Special behavior for ++Colors Colors& operator++( Colors &c ) { c = static_cast<Colors>( static_cast<int>(c) + 1 ); if ( c == Colors::END_OF_LIST ) c = Colors::Black; return c; }有没有一种方法可以实现算术运算符而无需转换为具有已定义运算符的类型?我什么也想不出来,但是投下了我.强制转换通常表示出现问题,并且必须有很好的理由使用它们.我希望该语言允许在无需强制使用特定类型的情况下实现操作符.
Is there a way to implement arithmetic operators without casting to a type with already defined operators? I can't think of any, but casting bothers me. Casts are usually indication of something wrong and there has to be a very good reason for their usage. I would expect the language to allow implementation of an operator to be achievable without forcing to a specific type.
更新2018年12月: 关于C ++ 17的论文之一似乎至少部分地通过允许枚举类变量与基础类型之间的转换来解决此问题: www.open-std/jtc1/sc22/wg21/docs/papers/2016/p0138r2.pdf
Update Dec 2018: One of the papers towards C++17 seems to address this at least partially by allowing conversions between enum class variable and the underlying type: www.open-std/jtc1/sc22/wg21/docs/papers/2016/p0138r2.pdf
推荐答案免播解决方案是使用switch.但是,您可以使用模板生成伪开关.原理是使用模板列表(或参数包)递归处理枚举的所有值.所以,这是我发现的3种方法.
The no-cast solution is to use switch. However, you can generate a pseudo-switch using templates. The principle is to recursively process all values of the enum using a template list (or a parameter pack). So, here are 3 methods I found.
测试枚举:
enum class Fruit { apple, banana, orange, pineapple, lemon };香草开关(住在此处):
Fruit& operator++(Fruit& f) { switch(f) { case Fruit::apple: return f = Fruit::banana; case Fruit::banana: return f = Fruit::orange; case Fruit::orange: return f = Fruit::pineapple; case Fruit::pineapple: return f = Fruit::lemon; case Fruit::lemon: return f = Fruit::apple; } }C ++ 03版本的方法(住在此处):
template<typename E, E v> struct EnumValue { static const E value = v; }; template<typename h, typename t> struct StaticList { typedef h head; typedef t tail; }; template<typename list, typename first> struct CyclicHead { typedef typename list::head item; }; template<typename first> struct CyclicHead<void,first> { typedef first item; }; template<typename E, typename list, typename first = typename list::head> struct Advance { typedef typename list::head lh; typedef typename list::tail lt; typedef typename CyclicHead<lt, first>::item next; static void advance(E& value) { if(value == lh::value) value = next::value; else Advance<E, typename list::tail, first>::advance(value); } }; template<typename E, typename f> struct Advance<E,void,f> { static void advance(E& value) { } }; /// Scalable way, C++03-ish typedef StaticList<EnumValue<Fruit,Fruit::apple>, StaticList<EnumValue<Fruit,Fruit::banana>, StaticList<EnumValue<Fruit,Fruit::orange>, StaticList<EnumValue<Fruit,Fruit::pineapple>, StaticList<EnumValue<Fruit,Fruit::lemon>, void > > > > > Fruit_values; Fruit& operator++(Fruit& f) { Advance<Fruit, Fruit_values>::advance(f); return f; }使用C ++ 11语言的方法(住在此处):
template<typename E, E first, E head> void advanceEnum(E& v) { if(v == head) v = first; } template<typename E, E first, E head, E next, E... tail> void advanceEnum(E& v) { if(v == head) v = next; else advanceEnum<E,first,next,tail...>(v); } template<typename E, E first, E... values> struct EnumValues { static void advance(E& v) { advanceEnum<E, first, first, values...>(v); } }; /// Scalable way, C++11-ish typedef EnumValues<Fruit, Fruit::apple, Fruit::banana, Fruit::orange, Fruit::pineapple, Fruit::lemon > Fruit_values11; Fruit& operator++(Fruit& f) { Fruit_values11::advance(f); return f; }(C ++-11的旧版本)
您也许可以通过添加一些预处理器来扩展,而无需重复值列表.
You may be able to extend by adding some preprocessor to remove the need to repeat the list of values.
更多推荐
实现枚举类的运算符
发布评论