Advertisement
DeadlyRedCube

Flag enum template magicks

Feb 6th, 2018
252
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.73 KB | None | 0 0
  1. // Helper to easily get the value of an enum as its underlying type (wraps the static cast to underlying_type, basically)
  2. template <typename t_enum>
  3. constexpr inline typename std::underlying_type<t_enum>::type EnumValue(const t_enum enumValue)
  4. {
  5.   CASSERT(std::is_enum<t_enum>::value);
  6.  
  7.   return static_cast<typename std::underlying_type<t_enum>::type>(enumValue);
  8. }
  9.  
  10.  
  11. // TIsEnumClass basically defaults to just "std::is_enum<t_enum>". However there's a specialization for where the decltype
  12. //  of t_enum(+EnumValue) matches t_enum, which is the case for standard enums (because +enum is valid) but not enum
  13. //  classes (because +enumclass is not). That specialization ends up as
  14. //  false_type, since anything that's true for cannot be an enum class.
  15. template <typename t_enum, typename = t_enum>
  16. struct TIsEnumClass : public std::is_enum<t_enum>
  17. {
  18. };
  19.  
  20.  
  21. template <typename t_enum>
  22. struct TIsEnumClass <t_enum, decltype(t_enum(+std::declval<t_enum>()))> : public std::false_type
  23. {
  24. };
  25.  
  26.  
  27. // 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.
  28. template<typename t_enum, typename = t_enum, typename = t_enum>
  29. struct TIsFlagEnumClass : public std::false_type
  30. {
  31. };
  32.  
  33.  
  34. template<typename t_enum>
  35. struct TIsFlagEnumClass
  36.   <t_enum,
  37.   decltype(t_enum::None),
  38.   decltype(t_enum::All)>
  39.   : public TIsEnumClass<t_enum>
  40. {
  41. };
  42.  
  43.  
  44. // A template declaration that is only enabled when the target is, in fact, a flags enum class.
  45. #define SFINAE_ENABLE_IF_IS_FLAG(t_enum) \
  46.   template<typename t_enum, typename std::enable_if<TIsFlagEnumClass<t_enum>::value, int>::type = 0>
  47.  
  48. // Now create our templated operator overloads
  49.  
  50. SFINAE_ENABLE_IF_IS_FLAG(t_enum)
  51. inline constexpr t_enum operator|(t_enum a, t_enum b)
  52. {
  53.   return static_cast<t_enum>(static_cast<typename std::underlying_type<t_enum>::type>(a)
  54.                             | static_cast<typename std::underlying_type<t_enum>::type>(b));
  55. }
  56.  
  57.  
  58. SFINAE_ENABLE_IF_IS_FLAG(t_enum)
  59. inline t_enum &operator|=(t_enum &a, t_enum b)
  60. {
  61.   a = a | b;
  62.   return a;
  63. }
  64.  
  65.  
  66. SFINAE_ENABLE_IF_IS_FLAG(t_enum)
  67. inline constexpr t_enum operator&(t_enum a, t_enum b)
  68. {
  69.   return static_cast<t_enum>(static_cast<typename std::underlying_type<t_enum>::type>(a)
  70.                             & static_cast<typename std::underlying_type<t_enum>::type>(b));
  71. }
  72.  
  73.  
  74. SFINAE_ENABLE_IF_IS_FLAG(t_enum)
  75. inline t_enum &operator&=(t_enum &a, t_enum b)
  76. {
  77.   a = a & b;
  78.   return a;
  79. }
  80.  
  81.  
  82. SFINAE_ENABLE_IF_IS_FLAG(t_enum)
  83. inline constexpr t_enum operator^(t_enum a, t_enum b)
  84. {
  85.   return static_cast<t_enum>(static_cast<typename std::underlying_type<t_enum>::type>(a)
  86.                             ^ static_cast<typename std::underlying_type<t_enum>::type>(b));
  87. }
  88.  
  89.  
  90. SFINAE_ENABLE_IF_IS_FLAG(t_enum)
  91. inline t_enum &operator^=(t_enum &a, t_enum b)
  92. {
  93.   a = a ^ b;
  94.   return a;
  95. }
  96.  
  97.  
  98. SFINAE_ENABLE_IF_IS_FLAG(t_enum)
  99. inline constexpr t_enum operator~(t_enum a)
  100. {
  101.   return static_cast<t_enum>(~static_cast<typename std::underlying_type<t_enum>::type>(a));
  102. }
  103.  
  104.  
  105. SFINAE_ENABLE_IF_IS_FLAG(t_enum)
  106. inline constexpr bool operator!(t_enum a)
  107. {
  108.   return !static_cast<typename std::underlying_type<t_enum>::type>(a);
  109. }
  110.  
  111.  
  112.  
  113. // 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.
  114. enum class SomeFlags
  115. {
  116.   F1 = 0x01,
  117.   F2 = 0x02,
  118.   F3 = 0x04,
  119.   F4 = 0x08,
  120.   F5 = 0x10,
  121.  
  122.   None = 0x00,
  123.   All = 0x1F,
  124. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement