diff options
| -rw-r--r-- | source/lib/include/newtype/concepts.hpp | 60 | ||||
| -rw-r--r-- | source/lib/include/newtype/impl/type_traits_extensions.hpp | 113 | ||||
| -rw-r--r-- | source/lib/include/newtype/newtype.hpp | 20 | ||||
| -rw-r--r-- | source/tests/src/relational_operators.cpp | 198 |
4 files changed, 141 insertions, 250 deletions
diff --git a/source/lib/include/newtype/concepts.hpp b/source/lib/include/newtype/concepts.hpp index 8f94a42..a50b2b3 100644 --- a/source/lib/include/newtype/concepts.hpp +++ b/source/lib/include/newtype/concepts.hpp @@ -42,6 +42,66 @@ namespace nt::concepts } noexcept; }; + template<typename SubjectType> + concept less_than_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs < rhs + } -> std::convertible_to<bool>; + }; + + template<typename SubjectType> + concept nothrow_less_than_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires less_than_comparable<SubjectType>; + { + lhs < rhs + } noexcept; + }; + + template<typename SubjectType> + concept less_than_equal_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs <= rhs + } -> std::convertible_to<bool>; + }; + + template<typename SubjectType> + concept nothrow_less_than_equal_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires less_than_equal_comparable<SubjectType>; + { + lhs <= rhs + } noexcept; + }; + + template<typename SubjectType> + concept greater_than_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs > rhs + } -> std::convertible_to<bool>; + }; + + template<typename SubjectType> + concept nothrow_greater_than_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires greater_than_comparable<SubjectType>; + { + lhs > rhs + } noexcept; + }; + + template<typename SubjectType> + concept greater_than_equal_comparable = requires(SubjectType lhs, SubjectType rhs) { + { + lhs >= rhs + } -> std::convertible_to<bool>; + }; + + template<typename SubjectType> + concept nothrow_greater_than_equal_comparable = requires(SubjectType lhs, SubjectType rhs) { + requires greater_than_equal_comparable<SubjectType>; + { + lhs >= rhs + } noexcept; + }; + } // namespace comparability inline namespace iostreamable diff --git a/source/lib/include/newtype/impl/type_traits_extensions.hpp b/source/lib/include/newtype/impl/type_traits_extensions.hpp index 22834f2..c2caf51 100644 --- a/source/lib/include/newtype/impl/type_traits_extensions.hpp +++ b/source/lib/include/newtype/impl/type_traits_extensions.hpp @@ -11,119 +11,6 @@ namespace nt::impl { - inline namespace relationally_comparable - { - - template<typename T, typename = void> - struct is_less_than_comparable : std::false_type - { - }; - - template<typename T> - struct is_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> : std::true_type - { - }; - - template<typename T> - auto constexpr is_less_than_comparable_v = is_less_than_comparable<T>::value; - - template<typename T, typename = void> - struct is_nothrow_less_than_comparable : std::false_type - { - }; - - 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 &>())> - { - }; - - template<typename T> - auto constexpr is_nothrow_less_than_comparable_v = is_nothrow_less_than_comparable<T>::value; - - template<typename T, typename = void> - struct is_greater_than_comparable : std::false_type - { - }; - - template<typename T> - struct is_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> : std::true_type - { - }; - - template<typename T> - auto constexpr is_greater_than_comparable_v = is_greater_than_comparable<T>::value; - - template<typename T, typename = void> - struct is_nothrow_greater_than_comparable : std::false_type - { - }; - - 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 &>())> - { - }; - - template<typename T> - auto constexpr is_nothrow_greater_than_comparable_v = is_nothrow_greater_than_comparable<T>::value; - - template<typename T, typename = void> - struct is_less_than_equal_to_comparable : std::false_type - { - }; - - 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 - { - }; - - template<typename T> - auto constexpr is_less_than_equal_to_comparable_v = is_less_than_equal_to_comparable<T>::value; - - template<typename T, typename = void> - struct is_nothrow_less_than_equal_to_comparable : std::false_type - { - }; - - 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 &>())> - { - }; - - template<typename T> - auto constexpr is_nothrow_less_than_equal_to_comparable_v = is_nothrow_less_than_equal_to_comparable<T>::value; - - template<typename T, typename = void> - struct is_greater_than_equal_to_comparable : std::false_type - { - }; - - 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 - { - }; - - template<typename T> - auto constexpr is_greater_than_equal_to_comparable_v = is_greater_than_equal_to_comparable<T>::value; - - template<typename T, typename = void> - struct is_nothrow_greater_than_equal_to_comparable : std::false_type - { - }; - - 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 &>())> - { - }; - - 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 arithmetic { diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp index e40097d..44bd1b8 100644 --- a/source/lib/include/newtype/newtype.hpp +++ b/source/lib/include/newtype/newtype.hpp @@ -299,38 +299,34 @@ namespace nt return lhs != rhs.decay(); } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::less_than_comparable BaseType, typename TagType, nt::contains<nt::Relational> auto DerivationClause> 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> + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_less_than_comparable<BaseType>) { return lhs.decay() < rhs.decay(); } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::greater_than_comparable BaseType, typename TagType, nt::contains<nt::Relational> auto DerivationClause> 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> + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_greater_than_comparable<BaseType>) { return lhs.decay() > rhs.decay(); } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::less_than_equal_comparable BaseType, typename TagType, nt::contains<nt::Relational> auto DerivationClause> 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> + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_less_than_equal_comparable<BaseType>) { return lhs.decay() <= rhs.decay(); } - template<typename BaseType, typename TagType, auto DerivationClause> + template<nt::concepts::greater_than_equal_comparable BaseType, typename TagType, nt::contains<nt::Relational> auto DerivationClause> 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> + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(nt::concepts::nothrow_greater_than_equal_comparable<BaseType>) { return lhs.decay() >= rhs.decay(); } diff --git a/source/tests/src/relational_operators.cpp b/source/tests/src/relational_operators.cpp index 95e1bd4..de6f7f3 100644 --- a/source/tests/src/relational_operators.cpp +++ b/source/tests/src/relational_operators.cpp @@ -9,190 +9,121 @@ #include <type_traits> #include <utility> -inline namespace traits_extensions -{ - - template<typename T, typename = void> - struct has_less_than : std::false_type - { - }; - - template<typename T> - struct has_less_than<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> : std::true_type - { - }; - - template<typename T> - auto constexpr has_less_than_v = has_less_than<T>::value; - - template<typename T> - auto constexpr has_nothrow_less_than_v = has_less_than_v<T> && noexcept(std::declval<T const &>() < std::declval<T const &>()); - - template<typename T, typename = void> - struct has_greater_than : std::false_type - { - }; - - template<typename T> - struct has_greater_than<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> : std::true_type - { - }; - - template<typename T> - auto constexpr has_greater_than_v = has_greater_than<T>::value; - - template<typename T> - auto constexpr has_nothrow_greater_than_v = has_less_than_v<T> && noexcept(std::declval<T const &>() < std::declval<T const &>()); - - template<typename T, typename = void> - struct has_less_than_equal_to : std::false_type - { - }; - - template<typename T> - struct has_less_than_equal_to<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>> : std::true_type - { - }; - - template<typename T> - auto constexpr has_less_than_equal_to_v = has_less_than_equal_to<T>::value; - - template<typename T> - auto constexpr has_nothrow_less_than_equal_to_v = has_less_than_v<T> && noexcept(std::declval<T const &>() < std::declval<T const &>()); - - template<typename T, typename = void> - struct has_greater_than_equal_to : std::false_type - { - }; - - template<typename T> - struct has_greater_than_equal_to<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>> : std::true_type - { - }; - - template<typename T> - auto constexpr has_greater_than_equal_to_v = has_greater_than_equal_to<T>::value; - - template<typename T> - auto constexpr has_nothrow_greater_than_equal_to_v = has_less_than_v<T> && noexcept(std::declval<T const &>() < std::declval<T const &>()); - -} // namespace traits_extensions - SCENARIO("Relational Operator Availability") { GIVEN("A new_type over a relationally comparable type not deriving nt::Relational") { using type_alias = nt::new_type<int, struct tag>; - static_assert(has_less_than_v<type_alias::base_type>); - static_assert(has_less_than_equal_to_v<type_alias::base_type>); - static_assert(has_greater_than_v<type_alias::base_type>); - static_assert(has_greater_than_equal_to_v<type_alias::base_type>); + static_assert(nt::concepts::less_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::less_than_equal_comparable<type_alias::base_type>); + static_assert(nt::concepts::greater_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::greater_than_equal_comparable<type_alias::base_type>); THEN("it does not have <") { - STATIC_REQUIRE_FALSE(has_less_than_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_comparable<type_alias>); } THEN("it does not have <=") { - STATIC_REQUIRE_FALSE(has_less_than_equal_to_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_equal_comparable<type_alias>); } THEN("it does not have >") { - STATIC_REQUIRE_FALSE(has_greater_than_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_comparable<type_alias>); } THEN("it does not have >=") { - STATIC_REQUIRE_FALSE(has_greater_than_equal_to_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_equal_comparable<type_alias>); } } GIVEN("A new_type over a relationally comparable type deriving nt::Relational") { using type_alias = nt::new_type<int, struct tag, deriving(nt::Relational)>; - static_assert(has_less_than_v<type_alias::base_type>); - static_assert(has_less_than_equal_to_v<type_alias::base_type>); - static_assert(has_greater_than_v<type_alias::base_type>); - static_assert(has_greater_than_equal_to_v<type_alias::base_type>); + static_assert(nt::concepts::less_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::less_than_equal_comparable<type_alias::base_type>); + static_assert(nt::concepts::greater_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::greater_than_equal_comparable<type_alias::base_type>); THEN("it does have <") { - STATIC_REQUIRE(has_less_than_v<type_alias>); + STATIC_REQUIRE(nt::concepts::less_than_comparable<type_alias>); } THEN("it does have <=") { - STATIC_REQUIRE(has_less_than_equal_to_v<type_alias>); + STATIC_REQUIRE(nt::concepts::less_than_equal_comparable<type_alias>); } THEN("it does have >") { - STATIC_REQUIRE(has_greater_than_v<type_alias>); + STATIC_REQUIRE(nt::concepts::greater_than_comparable<type_alias>); } THEN("it does have >=") { - STATIC_REQUIRE(has_greater_than_equal_to_v<type_alias>); + STATIC_REQUIRE(nt::concepts::greater_than_equal_comparable<type_alias>); } } GIVEN("A new_type over a type that is not relationally comparable not deriving nt::Relational") { using type_alias = nt::new_type<std::istream, struct tag>; - static_assert(!has_less_than_v<type_alias::base_type>); - static_assert(!has_less_than_equal_to_v<type_alias::base_type>); - static_assert(!has_greater_than_v<type_alias::base_type>); - static_assert(!has_greater_than_equal_to_v<type_alias::base_type>); + static_assert(!nt::concepts::less_than_comparable<type_alias::base_type>); + static_assert(!nt::concepts::less_than_equal_comparable<type_alias::base_type>); + static_assert(!nt::concepts::greater_than_comparable<type_alias::base_type>); + static_assert(!nt::concepts::greater_than_equal_comparable<type_alias::base_type>); THEN("it does not have <") { - STATIC_REQUIRE_FALSE(has_less_than_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_comparable<type_alias>); } THEN("it does not have <=") { - STATIC_REQUIRE_FALSE(has_less_than_equal_to_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_equal_comparable<type_alias>); } THEN("it does not have >") { - STATIC_REQUIRE_FALSE(has_greater_than_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_comparable<type_alias>); } THEN("it does not have >=") { - STATIC_REQUIRE_FALSE(has_greater_than_equal_to_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_equal_comparable<type_alias>); } } GIVEN("A new_type over a type that is not relationally comparable deriving nt::Relational") { using type_alias = nt::new_type<std::istream, struct tag, deriving(nt::Relational)>; - static_assert(!has_less_than_v<type_alias::base_type>); - static_assert(!has_less_than_equal_to_v<type_alias::base_type>); - static_assert(!has_greater_than_v<type_alias::base_type>); - static_assert(!has_greater_than_equal_to_v<type_alias::base_type>); + static_assert(!nt::concepts::less_than_comparable<type_alias::base_type>); + static_assert(!nt::concepts::less_than_equal_comparable<type_alias::base_type>); + static_assert(!nt::concepts::greater_than_comparable<type_alias::base_type>); + static_assert(!nt::concepts::greater_than_equal_comparable<type_alias::base_type>); THEN("it does not have <") { - STATIC_REQUIRE_FALSE(has_less_than_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_comparable<type_alias>); } THEN("it does not have <=") { - STATIC_REQUIRE_FALSE(has_less_than_equal_to_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::less_than_equal_comparable<type_alias>); } THEN("it does not have >") { - STATIC_REQUIRE_FALSE(has_greater_than_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_comparable<type_alias>); } THEN("it does not have >=") { - STATIC_REQUIRE_FALSE(has_greater_than_equal_to_v<type_alias>); + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_equal_comparable<type_alias>); } } } @@ -202,10 +133,10 @@ SCENARIO("Relational Comparisons") GIVEN("A new_type over a relationally comparable type deriving nt::Relational") { using type_alias = nt::new_type<int, struct tag, deriving(nt::Relational)>; - static_assert(has_less_than_v<type_alias::base_type>); - static_assert(has_less_than_equal_to_v<type_alias::base_type>); - static_assert(has_greater_than_v<type_alias::base_type>); - static_assert(has_greater_than_equal_to_v<type_alias::base_type>); + static_assert(nt::concepts::less_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::less_than_equal_comparable<type_alias::base_type>); + static_assert(nt::concepts::greater_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::greater_than_equal_comparable<type_alias::base_type>); THEN("comparing two instances using < yields the same result as it does for the base type") { @@ -238,29 +169,29 @@ SCENARIO("Nothrow Relational Comparison") GIVEN("A new_type over a nothrow relationally comparable type deriving nt::Relational") { using type_alias = nt::new_type<int, struct tag, deriving(nt::Relational)>; - static_assert(has_nothrow_less_than_v<type_alias::base_type>); - static_assert(has_nothrow_less_than_equal_to_v<type_alias::base_type>); - static_assert(has_nothrow_greater_than_v<type_alias::base_type>); - static_assert(has_nothrow_greater_than_equal_to_v<type_alias::base_type>); + static_assert(nt::concepts::nothrow_less_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::nothrow_less_than_equal_comparable<type_alias::base_type>); + static_assert(nt::concepts::nothrow_greater_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::nothrow_greater_than_equal_comparable<type_alias::base_type>); THEN("it is nothrow-comparable using < ") { - STATIC_REQUIRE(has_nothrow_less_than_v<type_alias>); + STATIC_REQUIRE(nt::concepts::nothrow_less_than_comparable<type_alias>); } THEN("it is nothrow-comparable using <= ") { - STATIC_REQUIRE(has_nothrow_less_than_equal_to_v<type_alias>); + STATIC_REQUIRE(nt::concepts::nothrow_less_than_equal_comparable<type_alias>); } THEN("it is nothrow-comparable using > ") { - STATIC_REQUIRE(has_nothrow_greater_than_v<type_alias>); + STATIC_REQUIRE(nt::concepts::nothrow_greater_than_comparable<type_alias>); } THEN("it is nothrow-comparable using >= ") { - STATIC_REQUIRE(has_nothrow_greater_than_equal_to_v<type_alias>); + STATIC_REQUIRE(nt::concepts::nothrow_greater_than_equal_comparable<type_alias>); } } @@ -268,36 +199,53 @@ SCENARIO("Nothrow Relational Comparison") { struct strange_type { - auto constexpr operator<(strange_type const & other) const noexcept(false) -> bool; - auto constexpr operator>(strange_type const & other) const noexcept(false) -> bool; - auto constexpr operator<=(strange_type const & other) const noexcept(false) -> bool; - auto constexpr operator>=(strange_type const & other) const noexcept(false) -> bool; + auto constexpr operator<(strange_type const &) const noexcept(false) -> bool + { + return false; + } + auto constexpr operator>(strange_type const &) const noexcept(false) -> bool + { + return false; + } + auto constexpr operator<=(strange_type const &) const noexcept(false) -> bool + { + return false; + } + auto constexpr operator>=(strange_type const &) const noexcept(false) -> bool + { + return false; + } }; using type_alias = nt::new_type<strange_type, struct tag, deriving(nt::Relational)>; - static_assert(has_less_than_v<type_alias::base_type> && !has_nothrow_less_than_v<type_alias::base_type>); - static_assert(has_less_than_equal_to_v<type_alias::base_type> && !has_nothrow_less_than_equal_to_v<type_alias::base_type>); - static_assert(has_greater_than_v<type_alias::base_type> && !has_nothrow_greater_than_v<type_alias::base_type>); - static_assert(has_greater_than_equal_to_v<type_alias::base_type> && !has_nothrow_greater_than_equal_to_v<type_alias::base_type>); + static_assert(nt::concepts::less_than_comparable<type_alias::base_type> && + !nt::concepts::nothrow_less_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::less_than_equal_comparable<type_alias::base_type> && + !nt::concepts::nothrow_less_than_equal_comparable<type_alias::base_type>); + static_assert(nt::concepts::greater_than_comparable<type_alias::base_type> && + !nt::concepts::nothrow_greater_than_comparable<type_alias::base_type>); + static_assert(nt::concepts::greater_than_equal_comparable<type_alias::base_type> && + !nt::concepts::nothrow_greater_than_equal_comparable<type_alias::base_type>); THEN("it is not nothrow-comparable using < ") { - STATIC_REQUIRE(has_less_than_v<type_alias> && !has_nothrow_less_than_v<type_alias>); + STATIC_REQUIRE(nt::concepts::less_than_comparable<type_alias> && !nt::concepts::nothrow_less_than_comparable<type_alias>); } THEN("it is not nothrow-comparable using <= ") { - STATIC_REQUIRE(has_less_than_equal_to_v<type_alias> && !has_nothrow_less_than_equal_to_v<type_alias>); + STATIC_REQUIRE(nt::concepts::less_than_equal_comparable<type_alias> && !nt::concepts::nothrow_less_than_equal_comparable<type_alias>); } THEN("it is not nothrow-comparable using > ") { - STATIC_REQUIRE(has_greater_than_v<type_alias> && !has_nothrow_greater_than_v<type_alias>); + STATIC_REQUIRE(nt::concepts::greater_than_comparable<type_alias> && !nt::concepts::nothrow_greater_than_comparable<type_alias>); } THEN("it is not nothrow-comparable using >= ") { - STATIC_REQUIRE(has_greater_than_equal_to_v<type_alias> && !has_nothrow_greater_than_equal_to_v<type_alias>); + STATIC_REQUIRE(nt::concepts::greater_than_equal_comparable<type_alias> && + !nt::concepts::nothrow_greater_than_equal_comparable<type_alias>); } } } |
