Created
November 2, 2016 07:07
-
-
Save remyroez/0e25f618a627c0b674124ba5c369f9a8 to your computer and use it in GitHub Desktop.
SFINAE enum にビット演算を提供する(写経)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
参考サイト