diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2019-12-29 16:37:11 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2019-12-29 16:37:11 +0100 |
| commit | 993b49d9b0aba3a9e60ee2bc86aa72b5ee69d063 (patch) | |
| tree | adff3291e1ecb8222a404f671600c590528288fc | |
| parent | a8d181abe5a64def14b0f90f6149a67cca354a3a (diff) | |
| download | newtype-993b49d9b0aba3a9e60ee2bc86aa72b5ee69d063.tar.xz newtype-993b49d9b0aba3a9e60ee2bc86aa72b5ee69d063.zip | |
new_type: extract type_traits extensions
| -rw-r--r-- | include/newtype/impl/type_traits_extensions.hpp | 518 | ||||
| -rw-r--r-- | include/newtype/new_type.hpp | 98 |
2 files changed, 565 insertions, 51 deletions
diff --git a/include/newtype/impl/type_traits_extensions.hpp b/include/newtype/impl/type_traits_extensions.hpp new file mode 100644 index 0000000..ae0c7d5 --- /dev/null +++ b/include/newtype/impl/type_traits_extensions.hpp @@ -0,0 +1,518 @@ +#ifndef NEWTYPE_IMPL_TYPE_TRAITS_EXTENSIONS_HPP +#define NEWTYPE_IMPL_TYPE_TRAITS_EXTENSIONS_HPP + +#include <iosfwd> +#include <type_traits> + +namespace nt::impl +{ + + inline namespace equality_comparable + { + + /** + * @brief A trait to test if a given type is comparable using operator== + * + * @tparam T The type to test + * @note This specialization forms the base case for non-equals-comparable T + */ + template<typename T, typename = void> + struct is_equality_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is comparable using operator== + * + * @tparam T The type to test + * @note This specialization forms the case for equals-comparable T + */ + template<typename T> + struct is_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>> : std::true_type + { + }; + + /** + * @brief A variable template to test if a given type is comparable using operator== + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_equality_comparable_v = is_equality_comparable<T>::value; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator== + * + * @tparam T The type to test + * @note This specialization forms the base case for non-noexcept equals-comparable or non-equals-comparable T + */ + template<typename T, typename = void> + struct is_nothrow_equality_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator== + * + * @tparam T The type to test + * @note This specialization forms the case for equals-comparable T detemining if T is noexcept comparable using operator== + */ + template<typename T> + struct is_nothrow_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() == std::declval<T const &>())> + { + }; + + /** + * @brief A variable template to test if a given type is noexcept comparable using operator== + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_nothrow_equality_comparable_v = is_nothrow_equality_comparable<T>::value; + + /** + * @brief A trait to test if a given type is comparable using operator!= + * + * @tparam T The type to test + * @note This specialization forms the base case for non-not-equals-comparable T + */ + template<typename T, typename = void> + struct is_inequality_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is comparable using operator!= + * + * @tparam T The type to test + * @note This specialization forms the case for not-equals-comparable T + */ + template<typename T> + struct is_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>> : std::true_type + { + }; + + /** + * @brief A variable template to test if a given type is comparable using operator!= + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_inequality_comparable_v = is_inequality_comparable<T>::value; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator!= + * + * @tparam T The type to test + * @note This specialization forms the base case for non-noexcept not-equals-comparable or non-not-equals-comparable T + */ + template<typename T, typename = void> + struct is_nothrow_inequality_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator== + * + * @tparam T The type to test + * @note This specialization forms the case for equals-comparable T detemining if T is noexcept comparable using operator!= + */ + template<typename T> + struct is_nothrow_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() != std::declval<T const &>())> + { + }; + + /** + * @brief A variable template to test if a given type is noexcept comparable using operator!= + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_nothrow_inequality_comparable_v = is_nothrow_inequality_comparable<T>::value; + + } // namespace equality_comparable + + inline namespace relationally_comparable + { + + /** + * @brief A trait to test if a given type is comparable using operator< + * + * @tparam T The type to test + * @note This specialization forms the base case for non-less-than-comparable T + */ + template<typename T, typename = void> + struct is_less_than_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is comparable using operator< + * + * @tparam T The type to test + * @note This specialization forms the case for less-than-comparable T + */ + template<typename T> + struct is_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> : std::true_type + { + }; + + /** + * @brief A variable template to test if a given type is comparable using operator< + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_less_than_comparable_v = is_less_than_comparable<T>::value; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator< + * + * @tparam T The type to test + * @note This specialization forms the base case for non-noexcept less-than-comparable or non-less-than-comparable T + */ + template<typename T, typename = void> + struct is_nothrow_less_than_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator< + * + * @tparam T The type to test + * @note This specialization forms the case for less-than-comparable T detemining if T is noexcept comparable using operator< + */ + template<typename T> + struct is_nothrow_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() < std::declval<T const &>())> + { + }; + + /** + * @brief A variable template to test if a given type is noexcept comparable using operator< + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_nothrow_less_than_comparable_v = is_nothrow_less_than_comparable<T>::value; + + /** + * @brief A trait to test if a given type is comparable using operator> + * + * @tparam T The type to test + * @note This specialization forms the base case for non-greater-than-comparable T + */ + template<typename T, typename = void> + struct is_greater_than_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is comparable using operator> + * + * @tparam T The type to test + * @note This specialization forms the case for greater-than-comparable T + */ + template<typename T> + struct is_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> : std::true_type + { + }; + + /** + * @brief A variable template to test if a given type is comparable using operator> + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_greater_than_comparable_v = is_greater_than_comparable<T>::value; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator> + * + * @tparam T The type to test + * @note This specialization forms the base case for non-noexcept greater-than-comparable or non-greater-than-comparable T + */ + template<typename T, typename = void> + struct is_nothrow_greater_than_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator> + * + * @tparam T The type to test + * @note This specialization forms the case for greater-than-comparable T detemining if T is noexcept comparable using operator> + */ + template<typename T> + struct is_nothrow_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() > std::declval<T const &>())> + { + }; + + /** + * @brief A variable template to test if a given type is noexcept comparable using operator> + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_nothrow_greater_than_comparable_v = is_nothrow_greater_than_comparable<T>::value; + + /** + * @brief A trait to test if a given type is comparable using operator<= + * + * @tparam T The type to test + * @note This specialization forms the base case for non-less-than-or-equal-to-comparable T + */ + template<typename T, typename = void> + struct is_less_than_equal_to_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is comparable using operator<= + * + * @tparam T The type to test + * @note This specialization forms the case for less-than-or-equal-to-comparable T + */ + template<typename T> + struct is_less_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>> : std::true_type + { + }; + + /** + * @brief A variable template to test if a given type is comparable using operator<= + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_less_than_equal_to_comparable_v = is_less_than_equal_to_comparable<T>::value; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator<= + * + * @tparam T The type to test + * @note This specialization forms the base case for non-noexcept less-than-or-equal-to-comparable or non-less-than-or-equal-to-comparable T + */ + template<typename T, typename = void> + struct is_nothrow_less_than_equal_to_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator<= + * + * @tparam T The type to test + * @note This specialization forms the case for less-than-or-equal-to-comparable T detemining if T is noexcept comparable using operator<= + */ + template<typename T> + struct is_nothrow_less_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() <= std::declval<T const &>())> + { + }; + + /** + * @brief A variable template to test if a given type is noexcept comparable using operator<= + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_nothrow_less_than_equal_to_comparable_v = is_nothrow_less_than_equal_to_comparable<T>::value; + + /** + * @brief A trait to test if a given type is comparable using operator>= + * + * @tparam T The type to test + * @note This specialization forms the base case for non-greater-than-or-equal-to-comparable T + */ + template<typename T, typename = void> + struct is_greater_than_equal_to_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is comparable using operator>= + * + * @tparam T The type to test + * @note This specialization forms the case for greater-than-or-equal-to-comparable T + */ + template<typename T> + struct is_greater_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>> + : std::true_type + { + }; + + /** + * @brief A variable template to test if a given type is comparable using operator>= + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_greater_than_equal_to_comparable_v = is_greater_than_equal_to_comparable<T>::value; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator>= + * + * @tparam T The type to test + * @note This specialization forms the base case for non-noexcept greater-than-or-equal-to-comparable or + * non-greater-than-or-equal-to-comparable T + */ + template<typename T, typename = void> + struct is_nothrow_greater_than_equal_to_comparable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is noexcept comparable using operator>= + * + * @tparam T The type to test + * @note This specialization forms the case for greater-than-or-equal-to-comparable T detemining if T is noexcept comparable using + * operator>= + */ + template<typename T> + struct is_nothrow_greater_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() >= std::declval<T const &>())> + { + }; + + /** + * @brief A variable template to test if a given type is noexcept comparable using operator>= + * + * @tparam T The type to test + */ + template<typename T> + auto constexpr is_nothrow_greater_than_equal_to_comparable_v = is_nothrow_greater_than_equal_to_comparable<T>::value; + } // namespace relationally_comparable + + inline namespace iostreamable + { + + /** + * @brief A trait to test if a given type is output streamable + * + * @tparam T The type to test + * @note This specialization forms the base case for non-output-streamable T + */ + template<typename StreamType, typename T, typename = void> + struct is_output_streamable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is output streamable + * + * @tparam T The type to test + * @note This specialization forms the case for output-streamable T + */ + template<typename StreamType, typename T> + struct is_output_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() << std::declval<T const &>())>> + : std::true_type + { + }; + + /** + * @brief A variable template to test if a given type is output streamable + * + * @tparam T The type to test + */ + template<typename StreamType, typename T> + auto constexpr is_output_streamable_v = is_output_streamable<StreamType, T>::value; + + /** + * @brief A trait to test if a given type is noexcept output streamable + * + * @tparam T The type to test + * @note This specialization forms the base case for non-noexcept output-streamable or non-output-streamable T + */ + template<typename StreamType, typename T, typename = void> + struct is_nothrow_output_streamable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is noexcept output streamable + * + * @tparam T The type to test + * @note This specialization forms the case for output-streamable T detemining if T is noexcept output-streamable + */ + template<typename StreamType, typename T> + struct is_nothrow_output_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() << std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<StreamType &>() << std::declval<T const &>())> + { + }; + + /** + * @brief A variable template to test if a given type is noexcept output streamable + * + * @tparam T The type to test + */ + template<typename StreamType, typename T> + auto constexpr is_nothrow_output_streamable_v = is_nothrow_output_streamable<StreamType, T>::value; + + /** + * @brief A trait to test if a given type is input streamable + * + * @tparam T The type to test + * @note This specialization forms the base case for non-input-streamable T + */ + template<typename StreamType, typename T, typename = void> + struct is_input_streamable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is input streamable + * + * @tparam T The type to test + * @note This specialization forms the case for input-streamable T + */ + template<typename StreamType, typename T> + struct is_input_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() >> std::declval<T &>())>> : std::true_type + { + }; + + /** + * @brief A variable template to test if a given type is input streamable + * + * @tparam T The type to test + */ + template<typename StreamType, typename T> + auto constexpr is_input_streamable_v = is_input_streamable<StreamType, T>::value; + + /** + * @brief A trait to test if a given type is noexcept input streamable + * + * @tparam T The type to test + * @note This specialization forms the base case for non-noexcept input-streamable or non-input-streamable T + */ + template<typename StreamType, typename T, typename = void> + struct is_nothrow_input_streamable : std::false_type + { + }; + + /** + * @brief A trait to test if a given type is noexcept input streamable + * + * @tparam T The type to test + * @note This specialization forms the case for input-streamable T detemining if T is noexcept input-streamable + */ + template<typename StreamType, typename T> + struct is_nothrow_input_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() >> std::declval<T &>())>> + : std::bool_constant<noexcept(std::declval<StreamType &>() >> std::declval<T &>())> + { + }; + + /** + * @brief A variable template to test if a given type is noexcept input streamable + * + * @tparam T The type to test + */ + template<typename StreamType, typename T> + auto constexpr is_nothrow_input_streamable_v = is_nothrow_input_streamable<StreamType, T>::value; + + } // namespace iostreamable + +} // namespace nt::impl + +#endif
\ No newline at end of file diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index 7f73daa..85f0d40 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -4,6 +4,7 @@ #include "newtype/derivable.hpp" #include "newtype/deriving.hpp" #include "newtype/impl/new_type_storage.hpp" +#include "newtype/impl/type_traits_extensions.hpp" #include "newtype/type.hpp" #include <istream> @@ -30,10 +31,10 @@ namespace nt static_assert(!std::is_void_v<std::remove_cv_t<BaseType>>, "The base type must not be possibly cv-qualified void"); template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV, typename CharType, typename StreamTraits> - auto friend - operator>>(std::basic_istream<CharType, StreamTraits> & input, new_type<BaseTypeT, TagTypeT, DerivationClauseV> & target) noexcept( - noexcept(std::declval<std::basic_istream<CharType, StreamTraits> &>() >> std::declval<BaseTypeT &>())) - -> std::enable_if_t<DerivationClauseV(nt::Read), std::basic_istream<CharType, StreamTraits>> &; + auto friend operator>>(std::basic_istream<CharType, StreamTraits> &, new_type<BaseTypeT, TagTypeT, DerivationClauseV> &) noexcept( + impl::is_nothrow_input_streamable_v<std::basic_istream<CharType, StreamTraits>, BaseTypeT>) + -> std::enable_if_t<DerivationClauseV(nt::Read) && impl::is_input_streamable_v<std::basic_istream<CharType, StreamTraits>, BaseTypeT>, + std::basic_istream<CharType, StreamTraits>> &; using super = impl::new_type_move_assignment<BaseType, TagType>; @@ -177,10 +178,10 @@ namespace nt * @return true iff. the base type comparison operator returns true, false otherwise. */ template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator==(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() == - std::declval<BaseType const &>())) - -> bool + auto constexpr + operator==(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_equality_comparable_v<BaseType>) + -> std::enable_if_t<impl::is_equality_comparable_v<BaseType>, bool> { return lhs.decay() == rhs.decay(); } @@ -193,10 +194,10 @@ namespace nt * @return true iff. the base type comparison operator returns true, false otherwise. */ template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator!=(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() != - std::declval<BaseType const &>())) - -> bool + auto constexpr + operator!=(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v<BaseType>) + -> std::enable_if_t<impl::is_inequality_comparable_v<BaseType>, bool> { return lhs.decay() != rhs.decay(); } @@ -204,50 +205,46 @@ namespace nt /** * @brief Check if one nt::new_type object is less-than an other * - * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational. Otherwise is is - * defined as deleted. + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational and the base type is + * less-than comparable. Otherwise is is defined as deleted. * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type * comparison operator is noexcept. * @return true iff. the base type comparison operator returns true, false otherwise. */ template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator<(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() < - std::declval<BaseType const &>())) - -> std::enable_if_t<DerivationClause(nt::Relational), bool> + auto constexpr + operator<(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_less_than_comparable_v<BaseType>) + -> std::enable_if_t<DerivationClause(nt::Relational) && impl::is_less_than_comparable_v<BaseType>, bool> { return lhs.decay() < rhs.decay(); } template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator<(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() < - std::declval<BaseType const &>())) - -> std::enable_if_t<!DerivationClause(nt::Relational), bool> = delete; + auto constexpr operator<(new_type<BaseType, TagType, DerivationClause> const &, new_type<BaseType, TagType, DerivationClause> const &) + -> std::enable_if_t<!DerivationClause(nt::Relational) || !impl::is_less_than_comparable_v<BaseType>, bool> = delete; /** * Check if one nt::new_type object is greater-than an other * - * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational. Otherwise is is - * defined as deleted. + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational and the base type is + * greater-than comparable. Otherwise is is defined as deleted. * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type * comparison operator is noexcept. * @return true iff. the base type comparison operator returns true, false otherwise. */ template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator>(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() > - std::declval<BaseType const &>())) - -> std::enable_if_t<DerivationClause(nt::Relational), bool> + auto constexpr + operator>(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_greater_than_comparable_v<BaseType>) + -> std::enable_if_t<DerivationClause(nt::Relational) && impl::is_greater_than_comparable_v<BaseType>, bool> { return lhs.decay() > rhs.decay(); } template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator>(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() > - std::declval<BaseType const &>())) - -> std::enable_if_t<!DerivationClause(nt::Relational), bool> = delete; + auto constexpr operator>(new_type<BaseType, TagType, DerivationClause> const &, new_type<BaseType, TagType, DerivationClause> const &) + -> std::enable_if_t<!DerivationClause(nt::Relational) || !impl::is_greater_than_comparable_v<BaseType>, bool> = delete; /** * Check if one nt::new_type object is less-than or equal-to an other @@ -258,19 +255,17 @@ namespace nt * @return true iff. the base type comparison operator returns true, false otherwise. */ template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator<=(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() <= - std::declval<BaseType const &>())) - -> std::enable_if_t<DerivationClause(nt::Relational), bool> + auto constexpr + operator<=(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_less_than_equal_to_comparable_v<BaseType>) + -> std::enable_if_t<DerivationClause(nt::Relational) && impl::is_less_than_equal_to_comparable_v<BaseType>, bool> { return lhs.decay() <= rhs.decay(); } template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator<=(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() <= - std::declval<BaseType const &>())) - -> std::enable_if_t<!DerivationClause(nt::Relational), bool> = delete; + auto constexpr operator<=(new_type<BaseType, TagType, DerivationClause> const &, new_type<BaseType, TagType, DerivationClause> const &) + -> std::enable_if_t<!DerivationClause(nt::Relational) || !impl::is_less_than_equal_to_comparable_v<BaseType>, bool> = delete; /** * Check if one nt::new_type object is greater-than or equal-to an other @@ -281,19 +276,18 @@ namespace nt * @return true iff. the base type comparison operator returns true, false otherwise. */ template<typename BaseType, typename TagType, auto DerivationClause> - auto constexpr operator>=(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() >= - std::declval<BaseType const &>())) - -> std::enable_if_t<DerivationClause(nt::Relational), bool> + auto constexpr + operator>=(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_greater_than_equal_to_comparable_v<BaseType>) + -> std::enable_if_t<DerivationClause(nt::Relational) && impl::is_greater_than_equal_to_comparable_v<BaseType>, bool> { return lhs.decay() >= rhs.decay(); } template<typename BaseType, typename TagType, auto DerivationClause> auto constexpr operator>=(new_type<BaseType, TagType, DerivationClause> const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() >= - std::declval<BaseType const &>())) - -> std::enable_if_t<!DerivationClause(nt::Relational), bool> = delete; + new_type<BaseType, TagType, DerivationClause> const & rhs) + -> std::enable_if_t<!DerivationClause(nt::Relational) || !impl::is_greater_than_equal_to_comparable_v<BaseType>, bool> = delete; /** * @brief Write the contained base type object to a standard output stream @@ -305,8 +299,9 @@ namespace nt */ template<typename BaseType, typename TagType, auto DerivationClause, typename CharType, typename StreamTraits> auto operator<<(std::basic_ostream<CharType, StreamTraits> & output, new_type<BaseType, TagType, DerivationClause> const & source) noexcept( - noexcept(std::declval<std::basic_ostream<CharType, StreamTraits> &>() << std::declval<BaseType const &>())) - -> std::enable_if_t<DerivationClause(nt::Show), std::basic_ostream<CharType, StreamTraits>> & + impl::is_nothrow_output_streamable_v<std::basic_ostream<CharType, StreamTraits>, BaseType>) + -> std::enable_if_t<DerivationClause(nt::Show) && impl::is_output_streamable_v<std::basic_ostream<CharType, StreamTraits>, BaseType>, + std::basic_ostream<CharType, StreamTraits>> & { return output << source.decay(); } @@ -321,8 +316,9 @@ namespace nt */ template<typename BaseType, typename TagType, auto DerivationClause, typename CharType, typename StreamTraits> auto operator>>(std::basic_istream<CharType, StreamTraits> & input, new_type<BaseType, TagType, DerivationClause> & target) noexcept( - noexcept(std::declval<std::basic_istream<CharType, StreamTraits> &>() >> std::declval<BaseType &>())) - -> std::enable_if_t<DerivationClause(nt::Read), std::basic_istream<CharType, StreamTraits>> & + impl::is_nothrow_input_streamable_v<std::basic_istream<CharType, StreamTraits>, BaseType>) + -> std::enable_if_t<DerivationClause(nt::Read) && impl::is_input_streamable_v<std::basic_istream<CharType, StreamTraits>, BaseType>, + std::basic_istream<CharType, StreamTraits>> & { return input >> target.m_value; } |
