这是你应该写一次,使用很多地方。
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上试过它。
这个问题与C++ 11有关?我建议使用'enum class'将C++ 11限定为这个问题。 – badola
这是相关的,因为在C++ 11中,您必须手动将其转换为整数,这是主要的一点。 –