Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Helper to easily get the value of an enum as its underlying type (wraps the static cast to underlying_type, basically)
- template <typename t_enum>
- constexpr inline typename std::underlying_type<t_enum>::type EnumValue(const t_enum enumValue)
- {
- CASSERT(std::is_enum<t_enum>::value);
- return static_cast<typename std::underlying_type<t_enum>::type>(enumValue);
- }
- // TIsEnumClass basically defaults to just "std::is_enum<t_enum>". However there's a specialization for where the decltype
- // of t_enum(+EnumValue) matches t_enum, which is the case for standard enums (because +enum is valid) but not enum
- // classes (because +enumclass is not). That specialization ends up as
- // false_type, since anything that's true for cannot be an enum class.
- template <typename t_enum, typename = t_enum>
- struct TIsEnumClass : public std::is_enum<t_enum>
- {
- };
- template <typename t_enum>
- struct TIsEnumClass <t_enum, decltype(t_enum(+std::declval<t_enum>()))> : public std::false_type
- {
- };
- // TIsFlagEnumClass defaults to false_type, but in the case where decltype of type members All and None matches the type, will then resolve to TIsEnumClass.
- template<typename t_enum, typename = t_enum, typename = t_enum>
- struct TIsFlagEnumClass : public std::false_type
- {
- };
- template<typename t_enum>
- struct TIsFlagEnumClass
- <t_enum,
- decltype(t_enum::None),
- decltype(t_enum::All)>
- : public TIsEnumClass<t_enum>
- {
- };
- // A template declaration that is only enabled when the target is, in fact, a flags enum class.
- #define SFINAE_ENABLE_IF_IS_FLAG(t_enum) \
- template<typename t_enum, typename std::enable_if<TIsFlagEnumClass<t_enum>::value, int>::type = 0>
- // Now create our templated operator overloads
- SFINAE_ENABLE_IF_IS_FLAG(t_enum)
- inline constexpr t_enum operator|(t_enum a, t_enum b)
- {
- return static_cast<t_enum>(static_cast<typename std::underlying_type<t_enum>::type>(a)
- | static_cast<typename std::underlying_type<t_enum>::type>(b));
- }
- SFINAE_ENABLE_IF_IS_FLAG(t_enum)
- inline t_enum &operator|=(t_enum &a, t_enum b)
- {
- a = a | b;
- return a;
- }
- SFINAE_ENABLE_IF_IS_FLAG(t_enum)
- inline constexpr t_enum operator&(t_enum a, t_enum b)
- {
- return static_cast<t_enum>(static_cast<typename std::underlying_type<t_enum>::type>(a)
- & static_cast<typename std::underlying_type<t_enum>::type>(b));
- }
- SFINAE_ENABLE_IF_IS_FLAG(t_enum)
- inline t_enum &operator&=(t_enum &a, t_enum b)
- {
- a = a & b;
- return a;
- }
- SFINAE_ENABLE_IF_IS_FLAG(t_enum)
- inline constexpr t_enum operator^(t_enum a, t_enum b)
- {
- return static_cast<t_enum>(static_cast<typename std::underlying_type<t_enum>::type>(a)
- ^ static_cast<typename std::underlying_type<t_enum>::type>(b));
- }
- SFINAE_ENABLE_IF_IS_FLAG(t_enum)
- inline t_enum &operator^=(t_enum &a, t_enum b)
- {
- a = a ^ b;
- return a;
- }
- SFINAE_ENABLE_IF_IS_FLAG(t_enum)
- inline constexpr t_enum operator~(t_enum a)
- {
- return static_cast<t_enum>(~static_cast<typename std::underlying_type<t_enum>::type>(a));
- }
- SFINAE_ENABLE_IF_IS_FLAG(t_enum)
- inline constexpr bool operator!(t_enum a)
- {
- return !static_cast<typename std::underlying_type<t_enum>::type>(a);
- }
- // So now that all that is there, if you have an enum class that you want to be a flags enum, you just have to make sure to give it "None" and "All" members, and it will automatically pick up all of the above operators. If you prefer, you could just auto-add those operators to ALL enum classes by changing TIsFlagEnumClass to TIsEnumClass in the SFINAE_ENABLE_IF_IS_FLAG macro.
- enum class SomeFlags
- {
- F1 = 0x01,
- F2 = 0x02,
- F3 = 0x04,
- F4 = 0x08,
- F5 = 0x10,
- None = 0x00,
- All = 0x1F,
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement