diff options
| -rw-r--r-- | source/lib/include/newtype/concepts.hpp | 31 | ||||
| -rw-r--r-- | source/lib/include/newtype/impl/type_traits_extensions.hpp | 59 | ||||
| -rw-r--r-- | source/lib/include/newtype/newtype.hpp | 34 | ||||
| -rw-r--r-- | source/tests/src/equality_comparison.cpp | 15 |
4 files changed, 55 insertions, 84 deletions
diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp index a29ba37..6db528c 100644 --- a/source/lib/include/newtype/concepts.hpp +++ b/source/lib/include/newtype/concepts.hpp @@ -7,6 +7,37 @@ namespace nt::concepts { + + template<typename SubjectType> + concept equality_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs == rhs + } -> std::convertible_to<bool>; + }; + + template<typename SubjectType> + concept nothrow_equality_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires equality_comparable<SubjectType>; + { + lhs == rhs + } noexcept; + }; + + template<typename SubjectType> + concept inequality_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs != rhs + } -> std::convertible_to<bool>; + }; + + template<typename SubjectType> + concept nothrow_inequality_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires inequality_comparable<SubjectType>; + { + lhs != rhs + } noexcept; + }; + template<typename SubjectType> concept hashable = requires(SubjectType subject) { { diff --git a/source/lib/include/newtype/impl/type_traits_extensions.hpp b/source/lib/include/newtype/impl/type_traits_extensions.hpp index bdd1cba..c4b9bee 100644 --- a/source/lib/include/newtype/impl/type_traits_extensions.hpp +++ b/source/lib/include/newtype/impl/type_traits_extensions.hpp @@ -11,65 +11,6 @@ namespace nt::impl { - inline namespace equality_comparable - { - - template<typename T, typename = void> - struct is_equality_comparable : std::false_type - { - }; - - template<typename T> - struct is_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>> : std::true_type - { - }; - - template<typename T> - auto constexpr is_equality_comparable_v = is_equality_comparable<T>::value; - - template<typename T, typename = void> - struct is_nothrow_equality_comparable : std::false_type - { - }; - - 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 &>())> - { - }; - - template<typename T> - auto constexpr is_nothrow_equality_comparable_v = is_nothrow_equality_comparable<T>::value; - - template<typename T, typename = void> - struct is_inequality_comparable : std::false_type - { - }; - - template<typename T> - struct is_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>> : std::true_type - { - }; - - template<typename T> - auto constexpr is_inequality_comparable_v = is_inequality_comparable<T>::value; - - template<typename T, typename = void> - struct is_nothrow_inequality_comparable : std::false_type - { - }; - - 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 &>())> - { - }; - - template<typename T> - auto constexpr is_nothrow_inequality_comparable_v = is_nothrow_inequality_comparable<T>::value; - - } // namespace equality_comparable - inline namespace relationally_comparable { diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp index b833c10..126c439 100644 --- a/source/lib/include/newtype/newtype.hpp +++ b/source/lib/include/newtype/newtype.hpp @@ -251,54 +251,52 @@ namespace nt } }; - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::equality_comparable BaseType, typename TagType, auto DerivationClause> 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> + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_equality_comparable<BaseType>) -> bool { return lhs.decay() == rhs.decay(); } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::equality_comparable BaseType, typename TagType, auto DerivationClause> + requires(DerivationClause(nt::EqBase)) auto constexpr operator==(new_type<BaseType, TagType, DerivationClause> const & lhs, - BaseType const & rhs) noexcept(impl::is_nothrow_equality_comparable_v<BaseType>) - -> std::enable_if_t<DerivationClause(nt::EqBase) && impl::is_equality_comparable_v<BaseType>, bool> + BaseType const & rhs) noexcept(nt::concepts::nothrow_equality_comparable<BaseType>) -> bool { return lhs.decay() == rhs; } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::equality_comparable BaseType, typename TagType, auto DerivationClause> + requires(DerivationClause(nt::EqBase)) auto constexpr operator==(BaseType const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_equality_comparable_v<BaseType>) - -> std::enable_if_t<DerivationClause(nt::EqBase) && impl::is_equality_comparable_v<BaseType>, bool> + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_equality_comparable<BaseType>) -> bool { return lhs == rhs.decay(); } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::inequality_comparable BaseType, typename TagType, auto DerivationClause> 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> + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_inequality_comparable<BaseType>) -> bool { return lhs.decay() != rhs.decay(); } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::inequality_comparable BaseType, typename TagType, auto DerivationClause> + requires(DerivationClause(nt::EqBase)) auto constexpr operator!=(new_type<BaseType, TagType, DerivationClause> const & lhs, - BaseType const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v<BaseType>) - -> std::enable_if_t<DerivationClause(nt::EqBase) && impl::is_inequality_comparable_v<BaseType>, bool> + BaseType const & rhs) noexcept(nt::concepts::nothrow_inequality_comparable<BaseType>) -> bool { return lhs.decay() != rhs; } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::inequality_comparable BaseType, typename TagType, auto DerivationClause> + requires(DerivationClause(nt::EqBase)) auto constexpr operator!=(BaseType const & lhs, - new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v<BaseType>) - -> std::enable_if_t<DerivationClause(nt::EqBase) && impl::is_inequality_comparable_v<BaseType>, bool> + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_inequality_comparable<BaseType>) -> bool { return lhs != rhs.decay(); } diff --git a/source/tests/src/equality_comparison.cpp b/source/tests/src/equality_comparison.cpp index d857d9b..0876dc2 100644 --- a/source/tests/src/equality_comparison.cpp +++ b/source/tests/src/equality_comparison.cpp @@ -1,3 +1,4 @@ +#include "newtype/concepts.hpp" #include "newtype/derivable.hpp" #include "newtype/deriving.hpp" #include "newtype/newtype.hpp" @@ -64,17 +65,17 @@ SCENARIO("Equality Comparison", "[compare]") { using type_alias = nt::new_type<int, struct tag>; - static_assert(noexcept(std::declval<type_alias::base_type>() == std::declval<type_alias::base_type>())); - static_assert(noexcept(std::declval<type_alias::base_type>() != std::declval<type_alias::base_type>())); + static_assert(nt::concepts::nothrow_equality_comparable<type_alias::base_type>); + static_assert(nt::concepts::nothrow_inequality_comparable<type_alias::base_type>); THEN("it is nothrow-equality-comparable") { - STATIC_REQUIRE(noexcept(std::declval<type_alias>() == std::declval<type_alias>())); + STATIC_REQUIRE(nt::concepts::nothrow_equality_comparable<type_alias>); } THEN("it is nothrow-inequality-comparable") { - STATIC_REQUIRE(noexcept(std::declval<type_alias>() != std::declval<type_alias>())); + STATIC_REQUIRE(nt::concepts::nothrow_inequality_comparable<type_alias>); } } @@ -88,12 +89,12 @@ SCENARIO("Equality Comparison", "[compare]") using type_alias = nt::new_type<not_nothrow_comparable, struct tag>; - static_assert(!noexcept(std::declval<type_alias::base_type>() == std::declval<type_alias::base_type>())); - static_assert(!noexcept(std::declval<type_alias::base_type>() != std::declval<type_alias::base_type>())); + static_assert(!nt::concepts::nothrow_equality_comparable<type_alias::base_type>); + static_assert(!nt::concepts::nothrow_inequality_comparable<type_alias::base_type>); THEN("it is not nothrow-equality-comparable") { - STATIC_REQUIRE_FALSE(noexcept(std::declval<type_alias>() == std::declval<type_alias>())); + STATIC_REQUIRE_FALSE(nt::concepts::nothrow_equality_comparable<type_alias>); } THEN("it is not nothrow-inequality-comparable") |
