在c#中,通过[flags]属性将枚举视为标志,但在c++中实现这一点的最佳方法是什么?
例如,我想写:
enum AnimalFlags
{
HasClaws = 1,
CanFly =2,
EatsFish = 4,
Endangered = 8
};
seahawk.flags = CanFly | EatsFish | Endangered;
然而,我得到编译器错误关于int/enum转换。除了生硬的角色转换,还有更好的表达方式吗?最好,我不想依赖第三方库(如boost或Qt)的构造。
编辑:如答案中所示,我可以通过声明seahawk来避免编译器错误。标记为int。但是,我希望有某种机制来执行类型安全,这样就不能编写seahawk了。flags = HasMaximizeButton。
我使用以下宏:
#define ENUM_FLAG_OPERATORS(T) \
inline T operator~ (T a) { return static_cast<T>( ~static_cast<std::underlying_type<T>::type>(a) ); } \
inline T operator| (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) | static_cast<std::underlying_type<T>::type>(b) ); } \
inline T operator& (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) & static_cast<std::underlying_type<T>::type>(b) ); } \
inline T operator^ (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) ^ static_cast<std::underlying_type<T>::type>(b) ); } \
inline T& operator|= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) |= static_cast<std::underlying_type<T>::type>(b) ); } \
inline T& operator&= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) &= static_cast<std::underlying_type<T>::type>(b) ); } \
inline T& operator^= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) ^= static_cast<std::underlying_type<T>::type>(b) ); }
它类似于上面提到的那些,但有几个改进:
它是类型安全的(它不假设基础类型是int型)
它不需要手动指定底层类型(与@LunarEclipse的答案相反)
它需要包含type_traits:
#include <type_traits>
你可以像下面这样使用struct:
struct UiFlags2 {
static const int
FULLSCREEN = 0x00000004, //api 16
HIDE_NAVIGATION = 0x00000002, //api 14
LAYOUT_HIDE_NAVIGATION = 0x00000200, //api 16
LAYOUT_FULLSCREEN = 0x00000400, //api 16
LAYOUT_STABLE = 0x00000100, //api 16
IMMERSIVE_STICKY = 0x00001000; //api 19
};
并像这样使用:
int flags = UiFlags2::FULLSCREEN | UiFlags2::HIDE_NAVIGATION;
所以你不需要int类型转换,它是直接可用的。
同样,它也像枚举类一样是范围分离的
c++标准明确讨论了这一点,请参见“17.5.2.1.3位掩码类型”部分:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf
给定这个“模板”,你会得到:
enum AnimalFlags : unsigned int
{
HasClaws = 1,
CanFly = 2,
EatsFish = 4,
Endangered = 8
};
constexpr AnimalFlags operator|(AnimalFlags X, AnimalFlags Y) {
return static_cast<AnimalFlags>(
static_cast<unsigned int>(X) | static_cast<unsigned int>(Y));
}
AnimalFlags& operator|=(AnimalFlags& X, AnimalFlags Y) {
X = X | Y; return X;
}
其他的运算符也一样。
还要注意“constexpr”,如果您希望编译器能够在编译时执行操作符,则需要使用它。
如果你正在使用c++ /CLI并且希望能够分配给ref类的enum成员,你需要使用跟踪引用:
AnimalFlags% operator|=(AnimalFlags% X, AnimalFlags Y) {
X = X | Y; return X;
}
注意:此示例不完整,请参见“17.5.2.1.3位掩码类型”小节获得完整的操作符集。