Skip to content

Instantly share code, notes, and snippets.

@remyroez
Created November 2, 2016 07:07
Show Gist options
  • Save remyroez/0e25f618a627c0b674124ba5c369f9a8 to your computer and use it in GitHub Desktop.
Save remyroez/0e25f618a627c0b674124ba5c369f9a8 to your computer and use it in GitHub Desktop.
SFINAE enum にビット演算を提供する(写経)
#include <type_traits>
#include <iostream>
template <typename T, typename = typename std::is_enum<T>::type>
struct safe_underlying_type { using type = T; };
template <typename T>
struct safe_underlying_type<T, std::true_type> { using type = std::underlying_type_t<T>; };
template <typename T>
using safe_underlying_type_t = typename safe_underlying_type<T>::type;
template <typename T>
constexpr safe_underlying_type_t<T> underlying_cast(T t) noexcept { return static_cast<safe_underlying_type_t<T>>(t); }
namespace concepts {
template <typename E, typename T = E>
struct provides_bitwise_operators : std::false_type {};
template <typename E, typename T = E>
constexpr bool provides_bitwise_operators_v = provides_bitwise_operators<E, T>::value;
namespace provides_bitwise_operators_detail {
template <typename T1, typename T2, bool force_lhs = false>
using result_t = std::enable_if_t<
(provides_bitwise_operators_v<T1, T2> || provides_bitwise_operators_v<T2, T1>)
&& std::is_same<safe_underlying_type_t<T1>, safe_underlying_type_t<T2>>::value,
std::conditional_t<(force_lhs || std::is_enum<T1>::value), T1, T2>
>;
template <typename T>
constexpr result_t<T, T> operator~(T flags) { return static_cast<T>(~underlying_cast(flags)); }
template <typename T1, typename T2>
constexpr result_t<T1, T2> operator|(T1 flags1, T2 flags2) { return result_t<T1, T2>(underlying_cast(flags1) | underlying_cast(flags2)); }
template <typename T1, typename T2>
constexpr result_t<T1, T2> operator&(T1 flags1, T2 flags2) { return result_t<T1, T2>(underlying_cast(flags1) & underlying_cast(flags2)); }
template <typename T1, typename T2>
constexpr result_t<T1, T2> operator^(T1 flags1, T2 flags2) { return result_t<T1, T2>(underlying_cast(flags1) ^ underlying_cast(flags2)); }
template <typename T1, typename T2>
constexpr result_t<T1, T2, true> &operator|=(T1 &flags1, T2 flags2) { return flags1 = static_cast<T1>(flags1 | flags2); }
template <typename T1, typename T2>
constexpr result_t<T1, T2, true> &operator&=(T1 &flags1, T2 flags2) { return flags1 = static_cast<T1>(flags1 & flags2); }
template <typename T1, typename T2>
constexpr result_t<T1, T2, true> &operator^=(T1 &flags1, T2 flags2) { return flags1 = static_cast<T1>(flags1 ^ flags2); }
} // namespace provides_bitwise_operators_detail
} // namespace concepts
using concepts::provides_bitwise_operators_detail::operator~;
using concepts::provides_bitwise_operators_detail::operator|;
using concepts::provides_bitwise_operators_detail::operator&;
using concepts::provides_bitwise_operators_detail::operator^;
using concepts::provides_bitwise_operators_detail::operator|=;
using concepts::provides_bitwise_operators_detail::operator&=;
using concepts::provides_bitwise_operators_detail::operator^=;
enum class foo : unsigned int { hoge = 0b0001, fuga = 0b0010 };
enum class bar : unsigned int { moge = 0b0100, muga = 0b1000 };
enum class baz : int { koge = 0b10000, kuga = 0b100000 };
namespace concepts {
template <> struct provides_bitwise_operators<foo> : std::true_type {};
template <> struct provides_bitwise_operators<foo, safe_underlying_type_t<foo>> : std::true_type {};
template <> struct provides_bitwise_operators<foo, bar> : std::true_type {};
template <> struct provides_bitwise_operators<foo, baz> : std::true_type {}; // failed
} // namespace concepts
int main()
{
auto a = foo::hoge;
auto b = a | foo::fuga;
auto c = a;
c |= foo::fuga;
auto d = ~foo::hoge;
auto e = foo::hoge | 0b1000U;
auto f = foo::hoge | bar::moge;
//auto g = foo::hoge | baz::koge; // baz
//auto h = foo::hoge | 0b1000; // int
std::cout << underlying_cast(a) << std::endl;
std::cout << underlying_cast(b) << std::endl;
std::cout << underlying_cast(c) << std::endl;
std::cout << underlying_cast(d) << std::endl;
std::cout << underlying_cast(e) << std::endl;
std::cout << underlying_cast(f) << std::endl;
return 0;
}
@remyroez
Copy link
Author

remyroez commented Nov 2, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment