/* * strong_type C++14/17/20 strong typedef library * * Copyright (C) Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/strong_type */ #ifndef ROLLBEAR_STRONG_TYPE_HPP_INCLUDED #define ROLLBEAR_STRONG_TYPE_HPP_INCLUDED #include #include #include #include #include #if __cplusplus >= 201703L #define STRONG_NODISCARD [[nodiscard]] #else #define STRONG_NODISCARD #endif #if defined(_MSC_VER) && !defined(__clang__) && __MSC_VER < 1922 #define STRONG_CONSTEXPR #else #define STRONG_CONSTEXPR constexpr #endif #ifndef STRONG_HAS_STD_FORMAT #define STRONG_HAS_STD_FORMAT 0 #endif #ifndef STRONG_HAS_FMT_FORMAT #define STRONG_HAS_FMT_FORMAT 0 #endif #if STRONG_HAS_STD_FORMAT #include #if !defined(__cpp_lib_format) || __cpp_lib_format < 201907 #undef STRONG_HAS_STD_FORMAT #define STRONG_HAS_STD_FORMAT 0 #endif #endif #if STRONG_HAS_FMT_FORMAT #include #endif namespace strong { namespace impl { template using WhenConstructible = std::enable_if_t::value>; } template using modifier = typename M::template modifier; struct uninitialized_t {}; static constexpr uninitialized_t uninitialized{}; struct default_constructible { template class modifier { }; }; namespace impl { template constexpr bool supports_default_construction(const ::strong::default_constructible::modifier*) { return true; } } template class type : public modifier>... { public: template {}>> explicit type(uninitialized_t) noexcept { } template (nullptr))> constexpr type() noexcept(noexcept(T{})) : val{} { } template >> constexpr explicit type( std::initializer_list us ) noexcept(noexcept(T{us})) : val{us} { } template ::value && (sizeof...(U) > 0)>> constexpr explicit type( U&& ... u) noexcept(std::is_nothrow_constructible::value) : val(std::forward(u)...) {} friend STRONG_CONSTEXPR void swap(type& a, type& b) noexcept( std::is_nothrow_move_constructible::value && std::is_nothrow_move_assignable::value ) { using std::swap; swap(a.val, b.val); } STRONG_NODISCARD constexpr T& value_of() & noexcept { return val;} STRONG_NODISCARD constexpr const T& value_of() const & noexcept { return val;} STRONG_NODISCARD constexpr T&& value_of() && noexcept { return std::move(val);} STRONG_NODISCARD friend constexpr T& value_of(type& t) noexcept { return t.val;} STRONG_NODISCARD friend constexpr const T& value_of(const type& t) noexcept { return t.val;} STRONG_NODISCARD friend constexpr T&& value_of(type&& t) noexcept { return std::move(t).val;} private: T val; }; namespace impl { template constexpr bool is_strong_type_func(const strong::type*) { return true;} constexpr bool is_strong_type_func(...) { return false;} template constexpr T underlying_type(strong::type*); } template struct is_strong_type : std::integral_constant(nullptr))> {}; namespace impl { template using WhenStrongType = std::enable_if_t>::value>; template using WhenNotStrongType = std::enable_if_t>::value>; } template ::value> struct underlying_type { using type = decltype(impl::underlying_type(static_cast(nullptr))); }; template struct underlying_type { using type = T; }; template using underlying_type_t = typename underlying_type::type; namespace impl { template< typename T, typename = impl::WhenNotStrongType> constexpr T && access(T &&t) noexcept { return std::forward(t); } template < typename T, typename = impl::WhenStrongType> STRONG_NODISCARD constexpr auto access(T&& t) noexcept -> decltype(value_of(std::forward(t))) { return value_of(std::forward(t)); } } struct equality { template class modifier; }; template class equality::modifier<::strong::type> { using type = ::strong::type; public: STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator==( const type& lh, const type& rh) noexcept(noexcept(std::declval() == std::declval())) -> decltype(std::declval() == std::declval()) { return value_of(lh) == value_of(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator!=( const type& lh, const type& rh) noexcept(noexcept(std::declval() != std::declval())) -> decltype(std::declval() != std::declval()) { return value_of(lh) != value_of(rh); } }; namespace impl { template class typed_equality { private: using TT = underlying_type_t; using OT = underlying_type_t; public: STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator==(const T& lh, const Other& rh) noexcept(noexcept(std::declval() == std::declval())) -> decltype(std::declval() == std::declval()) { return value_of(lh) == impl::access(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator==(const Other& lh, const T& rh) noexcept(noexcept(std::declval() == std::declval())) -> decltype(std::declval() == std::declval()) { return impl::access(lh) == value_of(rh) ; } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator!=(const T& lh, const Other rh) noexcept(noexcept(std::declval() != std::declval())) -> decltype(std::declval() != std::declval()) { return value_of(lh) != impl::access(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator!=(const Other& lh, const T& rh) noexcept(noexcept(std::declval() != std::declval())) -> decltype(std::declval() != std::declval()) { return impl::access(lh) != value_of(rh) ; } }; } template struct equality_with { template class modifier : public impl::typed_equality... { }; }; namespace impl { template class typed_ordering { private: using TT = underlying_type_t; using OT = underlying_type_t; public: STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator<(const T& lh, const Other& rh) noexcept(noexcept(std::declval() < std::declval())) -> decltype(std::declval() < std::declval()) { return value_of(lh) < impl::access(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator<(const Other& lh, const T& rh) noexcept(noexcept(std::declval() < std::declval())) -> decltype(std::declval() < std::declval()) { return impl::access(lh) < value_of(rh) ; } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator<=(const T& lh, const Other& rh) noexcept(noexcept(std::declval() <= std::declval())) -> decltype(std::declval() <= std::declval()) { return value_of(lh) <= impl::access(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator<=(const Other& lh, const T& rh) noexcept(noexcept(std::declval() <= std::declval())) -> decltype(std::declval() <= std::declval()) { return impl::access(lh) <= value_of(rh) ; } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator>(const T& lh, const Other& rh) noexcept(noexcept(std::declval() > std::declval())) -> decltype(std::declval() > std::declval()) { return value_of(lh) > impl::access(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator>(const Other& lh, const T& rh) noexcept(noexcept(std::declval() > std::declval())) -> decltype(std::declval() > std::declval()) { return impl::access(lh) > value_of(rh) ; } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator>=(const T& lh, const Other& rh) noexcept(noexcept(std::declval() >= std::declval())) -> decltype(std::declval() >= std::declval()) { return value_of(lh) >= impl::access(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator>=(const Other& lh, const T& rh) noexcept(noexcept(std::declval() >= std::declval())) -> decltype(std::declval() >= std::declval()) { return impl::access(lh) >= value_of(rh) ; } }; } template struct ordered_with { template class modifier : public impl::typed_ordering... { }; }; namespace impl { template struct require_copy_constructible { static constexpr bool value = std::is_copy_constructible>::value; static_assert(value, "underlying type must be copy constructible"); }; template struct require_move_constructible { static constexpr bool value = std::is_move_constructible>::value; static_assert(value, "underlying type must be move constructible"); }; template struct require_copy_assignable { static constexpr bool value = std::is_copy_assignable>::value; static_assert(value, "underlying type must be copy assignable"); }; template struct require_move_assignable { static constexpr bool value = std::is_move_assignable>::value; static_assert(value, "underlying type must be move assignable"); }; template struct valid_type; template <> struct valid_type {}; template struct require_semiregular : valid_type::value && require_move_constructible::value && require_copy_assignable::value && require_move_assignable::value> { }; } struct semiregular { template class modifier; }; template class semiregular::modifier<::strong::type> : public default_constructible::modifier , private impl::require_semiregular { }; struct regular { template class modifier : public semiregular::modifier , public equality::modifier { }; }; struct unique { template class modifier : private impl::valid_type< impl::require_move_constructible::value && impl::require_move_assignable::value > { public: constexpr modifier() = default; modifier(const modifier&) = delete; constexpr modifier(modifier&&) = default; modifier& operator=(const modifier&) = delete; constexpr modifier& operator=(modifier&&) = default; }; }; struct ordered { template class modifier; }; template class ordered::modifier<::strong::type> { using type = ::strong::type; public: STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator<( const type& lh, const type& rh) noexcept(noexcept(std::declval() < std::declval())) -> decltype(std::declval() < std::declval()) { return value_of(lh) < value_of(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator<=( const type& lh, const type& rh) noexcept(noexcept(std::declval() <= std::declval())) -> decltype(std::declval() <= std::declval()) { return value_of(lh) <= value_of(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator>( const type& lh, const type& rh) noexcept(noexcept(std::declval() > std::declval())) -> decltype(std::declval() > std::declval()) { return value_of(lh) > value_of(rh); } STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator>=( const type& lh, const type& rh) noexcept(noexcept(std::declval() >= std::declval())) -> decltype(std::declval() >= std::declval()) { return value_of(lh) >= value_of(rh); } }; struct ostreamable { template class modifier { public: friend std::ostream& operator<<( std::ostream &os, const T &t) { return os << value_of(t); } }; }; struct istreamable { template class modifier { public: friend std::istream& operator>>( std::istream &is, T &t) { return is >> value_of(t); } }; }; struct iostreamable { template class modifier : public ostreamable::modifier , public istreamable::modifier { }; }; struct incrementable { template class modifier { public: friend STRONG_CONSTEXPR T& operator++(T& t) noexcept(noexcept(++std::declval().value_of())) { ++value_of(t); return t; } friend STRONG_CONSTEXPR T operator++(T& t, int) { auto copy = t; ++t; return copy; } }; }; struct decrementable { template class modifier { public: friend STRONG_CONSTEXPR T& operator--(T& t) noexcept(noexcept(--std::declval().value_of())) { --value_of(t); return t; } friend STRONG_CONSTEXPR T operator--(T& t, int) { auto copy = t; --t; return copy; } }; }; struct bicrementable { template class modifier : public incrementable::modifier , public decrementable::modifier { }; }; struct boolean { template class modifier { public: explicit STRONG_CONSTEXPR operator bool() const noexcept(noexcept(static_cast(value_of(std::declval())))) { const auto& self = static_cast(*this); return static_cast(value_of(self)); } }; }; struct hashable { template class modifier{}; }; struct difference { template class modifier; }; template class difference::modifier<::strong::type> : public ordered::modifier<::strong::type> , public equality::modifier<::strong::type> { using type = ::strong::type; public: friend STRONG_CONSTEXPR type& operator+=(type& lh, const type& rh) noexcept(noexcept(value_of(lh) += value_of(rh))) { value_of(lh) += value_of(rh); return lh; } friend STRONG_CONSTEXPR type& operator-=(type& lh, const type& rh) noexcept(noexcept(value_of(lh) -= value_of(rh))) { value_of(lh) -= value_of(rh); return lh; } friend STRONG_CONSTEXPR type& operator*=(type& lh, const T& rh) noexcept(noexcept(value_of(lh) *= rh)) { value_of(lh) *= rh; return lh; } friend STRONG_CONSTEXPR type& operator/=(type& lh, const T& rh) noexcept(noexcept(value_of(lh) /= rh)) { value_of(lh) /= rh; return lh; } template ()%= std::declval())> friend STRONG_CONSTEXPR type& operator%=(type& lh, const T& rh) noexcept(noexcept(value_of(lh) %= rh)) { value_of(lh)%= rh; return lh; } friend STRONG_CONSTEXPR type operator+(type lh, const type& rh) { lh += rh; return lh; } friend STRONG_CONSTEXPR type operator-(type lh, const type& rh) { lh -= rh; return lh; } friend STRONG_CONSTEXPR type operator*(type lh, const T& rh) { lh *= rh; return lh; } friend STRONG_CONSTEXPR type operator*(const T& lh, type rh) { rh *= lh; return rh; } friend STRONG_CONSTEXPR type operator/(type lh, const T& rh) { lh /= rh; return lh; } friend STRONG_CONSTEXPR T operator/(const type& lh, const type& rh) { return value_of(lh) / value_of(rh); } template () %= std::declval())> friend STRONG_CONSTEXPR type operator%(type lh, const T& rh) noexcept(noexcept(lh%= rh)) { lh %= rh; return lh; } template () % std::declval())> friend STRONG_CONSTEXPR T operator%(type lh, type rh) noexcept(noexcept(value_of(lh) % value_of(rh))) { return value_of(lh) % value_of(rh); } }; template struct affine_point { template class modifier; }; namespace impl { template using void_t = void; template struct subtractable : std::false_type {}; template struct subtractable() - std::declval())>> : std::true_type {}; } template template class affine_point::modifier<::strong::type> { using type = ::strong::type; static_assert(impl::subtractable::value, "it must be possible to subtract instances of your underlying type"); using base_diff_type = decltype(std::declval() - std::declval()); public: using difference = std::conditional_t{}, strong::type, D>; static_assert(std::is_constructible::value, ""); STRONG_NODISCARD friend STRONG_CONSTEXPR difference operator-( const type& lh, const type& rh) { return difference(value_of(lh) - value_of(rh)); } friend STRONG_CONSTEXPR type& operator+=( type& lh, const difference& d) noexcept(noexcept(value_of(lh) += impl::access(d))) { value_of(lh) += impl::access(d); return lh; } friend STRONG_CONSTEXPR type& operator-=( type& lh, const difference& d) noexcept(noexcept(value_of(lh) -= impl::access(d))) { value_of(lh) -= impl::access(d); return lh; } STRONG_NODISCARD friend STRONG_CONSTEXPR type operator+( type lh, const difference& d) { return lh += d; } STRONG_NODISCARD friend STRONG_CONSTEXPR type operator+( const difference& d, type rh) { return rh+= d; } STRONG_NODISCARD friend STRONG_CONSTEXPR type operator-( type lh, const difference& d) { return lh -= d; } }; struct pointer { template class modifier; }; template class pointer::modifier<::strong::type> { using type = strong::type; public: template STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator==( const type& t, std::nullptr_t) noexcept(noexcept(std::declval() == nullptr)) -> decltype(std::declval() == nullptr) { return value_of(t) == nullptr; } template STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator==( std::nullptr_t, const type& t) noexcept(noexcept(nullptr == std::declval())) -> decltype(nullptr == std::declval()) { return value_of(t) == nullptr; } template STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator!=( const type& t, std::nullptr_t) noexcept(noexcept(std::declval() != nullptr)) -> decltype(std::declval() != nullptr) { return value_of(t) != nullptr; } template STRONG_NODISCARD friend STRONG_CONSTEXPR auto operator!=( std::nullptr_t, const type& t) noexcept(noexcept(nullptr != std::declval())) -> decltype(nullptr != std::declval()) { return value_of(t) != nullptr; } STRONG_NODISCARD STRONG_CONSTEXPR decltype(*std::declval()) operator*() const { auto& self = static_cast(*this); return *value_of(self); } STRONG_NODISCARD STRONG_CONSTEXPR decltype(&(*std::declval())) operator->() const { return &operator*();} }; struct arithmetic { template class modifier { public: STRONG_NODISCARD friend STRONG_CONSTEXPR T operator-( const T &lh) { return T{-value_of(lh)}; } friend STRONG_CONSTEXPR T& operator+=( T &lh, const T &rh) noexcept(noexcept(value_of(lh) += value_of(rh))) { value_of(lh) += value_of(rh); return lh; } friend STRONG_CONSTEXPR T& operator-=( T &lh, const T &rh) noexcept(noexcept(value_of(lh) -= value_of(rh))) { value_of(lh) -= value_of(rh); return lh; } friend STRONG_CONSTEXPR T& operator*=( T &lh, const T &rh) noexcept(noexcept(value_of(lh) *= value_of(rh))) { value_of(lh) *= value_of(rh); return lh; } friend STRONG_CONSTEXPR T& operator/=( T &lh, const T &rh) noexcept(noexcept(value_of(lh) /= value_of(rh))) { value_of(lh) /= value_of(rh); return lh; } template ()) % value_of(std::declval()))> friend STRONG_CONSTEXPR T& operator%=( T &lh, const T &rh) noexcept(noexcept(value_of(lh) %= value_of(rh))) { value_of(lh) %= value_of(rh); return lh; } STRONG_NODISCARD friend STRONG_CONSTEXPR T operator+( T lh, const T &rh) { lh += rh; return lh; } STRONG_NODISCARD friend STRONG_CONSTEXPR T operator-( T lh, const T &rh) { lh -= rh; return lh; } STRONG_NODISCARD friend STRONG_CONSTEXPR T operator*( T lh, const T &rh) { lh *= rh; return lh; } STRONG_NODISCARD friend STRONG_CONSTEXPR T operator/( T lh, const T &rh) { lh /= rh; return lh; } template ()) % value_of(std::declval()))> STRONG_NODISCARD friend STRONG_CONSTEXPR T operator%( T lh, const T &rh) { lh %= rh; return lh; } }; }; struct bitarithmetic { template class modifier { public: friend STRONG_CONSTEXPR T& operator&=( T &lh, const T &rh) noexcept(noexcept(value_of(lh) &= value_of(rh))) { value_of(lh) &= value_of(rh); return lh; } friend STRONG_CONSTEXPR T& operator|=( T &lh, const T &rh) noexcept(noexcept(value_of(lh) |= value_of(rh))) { value_of(lh) |= value_of(rh); return lh; } friend STRONG_CONSTEXPR T& operator^=( T &lh, const T &rh) noexcept(noexcept(value_of(lh) ^= value_of(rh))) { value_of(lh) ^= value_of(rh); return lh; } template friend STRONG_CONSTEXPR T& operator<<=( T &lh, C c) noexcept(noexcept(value_of(lh) <<= c)) { value_of(lh) <<= c; return lh; } template friend STRONG_CONSTEXPR T& operator>>=( T &lh, C c) noexcept(noexcept(value_of(lh) >>= c)) { value_of(lh) >>= c; return lh; } STRONG_NODISCARD friend STRONG_CONSTEXPR T operator~( const T &lh) { auto v = value_of(lh); v = ~v; return T(v); } STRONG_NODISCARD friend STRONG_CONSTEXPR T operator&( T lh, const T &rh) { lh &= rh; return lh; } STRONG_NODISCARD friend STRONG_CONSTEXPR T operator|( T lh, const T &rh) { lh |= rh; return lh; } STRONG_NODISCARD friend STRONG_CONSTEXPR T operator^( T lh, const T &rh) { lh ^= rh; return lh; } template STRONG_NODISCARD friend STRONG_CONSTEXPR T operator<<( T lh, C c) { lh <<= c; return lh; } template STRONG_NODISCARD friend STRONG_CONSTEXPR T operator>>( T lh, C c) { lh >>= c; return lh; } }; }; template struct indexed { template class modifier; }; template <> struct indexed { template class modifier; template class modifier> { using ref = T&; using cref = const T&; using rref = T&&; using type = strong::type; public: template STRONG_NODISCARD auto operator[]( const I &i) const & noexcept(noexcept(std::declval()[impl::access(i)])) -> decltype(std::declval()[impl::access(i)]) { auto& self = static_cast(*this); return value_of(self)[impl::access(i)]; } template STRONG_NODISCARD auto operator[]( const I &i) & noexcept(noexcept(std::declval()[impl::access(i)])) -> decltype(std::declval()[impl::access(i)]) { auto& self = static_cast(*this); return value_of(self)[impl::access(i)]; } template STRONG_NODISCARD auto operator[]( const I &i) && noexcept(noexcept(std::declval()[impl::access(i)])) -> decltype(std::declval()[impl::access(i)]) { auto& self = static_cast(*this); return value_of(std::move(self))[impl::access(i)]; } template STRONG_NODISCARD auto at( const I &i) const & -> decltype(std::declval().at(impl::access(i))) { auto& self = static_cast(*this); return value_of(self).at(impl::access(i)); } template STRONG_NODISCARD auto at( const I &i) & -> decltype(std::declval().at(impl::access(i))) { auto& self = static_cast(*this); return value_of(self).at(impl::access(i)); } template STRONG_NODISCARD auto at( const I &i) && -> decltype(std::declval().at(impl::access(i))) { auto& self = static_cast(*this); return value_of(std::move(self)).at(impl::access(i)); } }; }; template template class indexed::modifier> { using type = ::strong::type; public: STRONG_NODISCARD auto operator[]( const I& i) const & noexcept(noexcept(std::declval()[impl::access(i)])) -> decltype(std::declval()[impl::access(i)]) { auto& self = static_cast(*this); return value_of(self)[impl::access(i)]; } STRONG_NODISCARD auto operator[]( const I& i) & noexcept(noexcept(std::declval()[impl::access(i)])) -> decltype(std::declval()[impl::access(i)]) { auto& self = static_cast(*this); return value_of(self)[impl::access(i)]; } STRONG_NODISCARD auto operator[]( const I& i) && noexcept(noexcept(std::declval()[impl::access(i)])) -> decltype(std::declval()[impl::access(i)]) { auto& self = static_cast(*this); return value_of(std::move(self))[impl::access(i)]; } template STRONG_NODISCARD auto at( const I& i) const & -> decltype(std::declval().at(impl::access(i))) { auto& self = static_cast(*this); return value_of(self).at(impl::access(i)); } template STRONG_NODISCARD auto at( const I& i) & -> decltype(std::declval().at(impl::access(i))) { auto& self = static_cast(*this); return value_of(self).at(impl::access(i)); } template STRONG_NODISCARD auto at( const I& i) && -> decltype(std::declval().at(impl::access(i))) { auto& self = static_cast(*this); return value_of(std::move(self)).at(impl::access(i)); } }; class iterator { public: template >::iterator_category> class modifier : public pointer::modifier , public equality::modifier , public incrementable::modifier { public: using difference_type = typename std::iterator_traits>::difference_type; using value_type = typename std::iterator_traits>::value_type; using pointer = typename std::iterator_traits>::value_type; using reference = typename std::iterator_traits>::reference; using iterator_category = typename std::iterator_traits>::iterator_category; }; template class modifier : public modifier , public decrementable::modifier { }; template class modifier : public modifier , public affine_point>::difference_type>::template modifier , public indexed<>::modifier , public ordered::modifier { }; }; class range { public: template class modifier; }; template class range::modifier> { using type = ::strong::type; using r_iterator = decltype(std::declval().begin()); using r_const_iterator = decltype(std::declval().begin()); public: using iterator = ::strong::type; using const_iterator = ::strong::type; iterator begin() noexcept(noexcept(std::declval().begin())) { auto& self = static_cast(*this); return iterator{value_of(self).begin()}; } iterator end() noexcept(noexcept(std::declval().end())) { auto& self = static_cast(*this); return iterator{value_of(self).end()}; } const_iterator cbegin() const noexcept(noexcept(std::declval().begin())) { auto& self = static_cast(*this); return const_iterator{value_of(self).begin()}; } const_iterator cend() const noexcept(noexcept(std::declval().end())) { auto& self = static_cast(*this); return const_iterator{value_of(self).end()}; } const_iterator begin() const noexcept(noexcept(std::declval().begin())) { auto& self = static_cast(*this); return const_iterator{value_of(self).begin()}; } const_iterator end() const noexcept(noexcept(std::declval().end())) { auto& self = static_cast(*this); return const_iterator{value_of(self).end()}; } }; namespace impl { template struct converter { STRONG_CONSTEXPR explicit operator D() const noexcept(noexcept(static_cast(std::declval&>()))) { auto& self = static_cast(*this); return static_cast(value_of(self)); } }; template struct implicit_converter { STRONG_CONSTEXPR operator D() const noexcept(noexcept(static_cast(std::declval&>()))) { auto& self = static_cast(*this); return static_cast(value_of(self)); } }; } template struct convertible_to { template struct modifier : impl::converter... { }; }; template struct implicitly_convertible_to { template struct modifier : impl::implicit_converter... { }; }; struct formattable { template class modifier{}; }; } namespace std { template struct hash<::strong::type> : std::conditional_t< std::is_base_of< ::strong::hashable::modifier< ::strong::type >, ::strong::type >::value, hash, std::false_type> { using type = ::strong::type; decltype(auto) operator()( const ::strong::hashable::modifier& t) const noexcept(noexcept(std::declval>()(value_of(std::declval())))) { auto& tt = static_cast(t); return hash::operator()(value_of(tt)); } }; template struct is_arithmetic<::strong::type> : is_base_of<::strong::arithmetic::modifier<::strong::type>, ::strong::type> { }; #if STRONG_HAS_STD_FORMAT template struct formatter<::strong::type, Char, std::enable_if_t< std::is_base_of< ::strong::formattable::modifier< ::strong::type >, ::strong::type >::value >> : formatter { using type = ::strong::type; template STRONG_CONSTEXPR decltype(auto) format(const ::strong::formattable::modifier& t, FormatContext& fc) noexcept(noexcept(std::declval>().format(value_of(std::declval()), fc))) { const auto& tt = static_cast(t); return formatter::format(value_of(tt), fc); } }; #endif } #if STRONG_HAS_FMT_FORMAT namespace fmt { template struct formatter<::strong::type, Char, std::enable_if_t< std::is_base_of< ::strong::formattable::modifier< ::strong::type >, ::strong::type >::value >> : formatter { using type = ::strong::type; template STRONG_CONSTEXPR decltype(auto) format(const ::strong::formattable::modifier& t, FormatContext& fc) noexcept(noexcept(std::declval>().format(value_of(std::declval()), fc))) { const auto& tt = static_cast(t); return formatter::format(value_of(tt), fc); } }; } #endif #endif //ROLLBEAR_STRONG_TYPE_HPP_INCLUDED