From b196e2c10ed8823c681623dfd7bc09b0eb3ad1d2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Jan 2020 22:38:18 +0100 Subject: new_type: implement support for base comparison --- doc/src/index.rst | 54 +++++++++++++++++++++++++++-- include/newtype/new_type.hpp | 62 +++++++++++++++++++++++++++++++++ test/src/equality_comparison_suite.cpp | 63 ++++++++++++++++++++++++++++------ 3 files changed, 166 insertions(+), 13 deletions(-) diff --git a/doc/src/index.rst b/doc/src/index.rst index 3ef593d..0a92d90 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -178,6 +178,30 @@ Equality Comparison Operators .. versionadded:: 1.0.0 +.. cpp:function:: template \ + constexpr bool operator==(new_type const &,\ + BaseType const &) + + **noexcept specification:** This comparison operator shall be noexcept iff. :cpp:type:`new_type::base_type` is nothrow equals-comparable. + + **enablement:** This operator shall be available iff. a) :cpp:type:`new_type::base_type` supports comparison using the operator :literal:`==` and b) the derivation clause contains :cpp:var:`EqBase` + + .. versionadded:: 1.0.0 + +.. cpp:function:: template \ + constexpr bool operator==(BaseType const &,\ + new_type const &) + + **noexcept specification:** This comparison operator shall be noexcept iff. :cpp:type:`new_type::base_type` is nothrow equals-comparable. + + **enablement:** This operator shall be available iff. a) :cpp:type:`new_type::base_type` supports comparison using the operator :literal:`==` and b) the derivation clause contains :cpp:var:`EqBase` + + .. versionadded:: 1.0.0 + .. cpp:function:: template \ @@ -190,6 +214,30 @@ Equality Comparison Operators .. versionadded:: 1.0.0 +.. cpp:function:: template \ + constexpr bool operator!=(new_type const &,\ + BaseType const &) + + **noexcept specification:** This comparison operator shall be noexcept iff. :cpp:type:`new_type::base_type` is nothrow equals-comparable. + + **enablement:** This operator shall be available iff. a) :cpp:type:`new_type::base_type` supports comparison using the operator :literal:`!=` and b) the derivation clause contains :cpp:var:`EqBase` + + .. versionadded:: 1.0.0 + +.. cpp:function:: template \ + constexpr bool operator!=(BaseType const &,\ + new_type const &) + + **noexcept specification:** This comparison operator shall be noexcept iff. :cpp:type:`new_type::base_type` is nothrow equals-comparable. + + **enablement:** This operator shall be available iff. a) :cpp:type:`new_type::base_type` supports comparison using the operator :literal:`!=` and b) the derivation clause contains :cpp:var:`EqBase` + + .. versionadded:: 1.0.0 + Relational Comparison Operators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -355,8 +403,8 @@ This header defines the alias template :cpp:type:`derivable` as well as the set Alias template :cpp:type:`derivable` ------------------------------------ -.. cpp:type:: template \ - derivable = type +.. cpp:struct:: template \ + derivable .. versionadded:: 1.0.0 @@ -373,7 +421,7 @@ Standard derivation tags .. cpp:var:: auto constexpr EqBase = derivable{} - This tag enables the derivation of "Equality comparison with base type" operators :literal:`==` and :literal:`!=` + This tag enables the derivation of "Equality comparison with base type" operators :cpp:func:`template\ constexpr bool nt::operator==(BaseType const &, new_type const &)`, :cpp:func:`template\ constexpr bool nt::operator==(new_type const &, BaseType const &)` :cpp:func:`template\ constexpr bool nt::operator!=(BaseType const &, new_type const &)`, and :cpp:func:`template\ constexpr bool nt::operator!=(new_type const &, BaseType const &)` By virtue of its nature, deriving this feature compromises the strength of the given :cpp:class:`new_type`. .. versionadded:: 1.0.0 diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index d22732a..b599c45 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -228,6 +228,37 @@ namespace nt return lhs.decay() == rhs.decay(); } + /** + * @brief Compare an instance of a given nt::new_type with an object of its base type + * + * @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 + auto constexpr operator==(new_type const & lhs, + BaseType const & rhs) noexcept(impl::is_nothrow_equality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs.decay() == rhs; + } + + /** + * @brief Compare an instance of the base type with an instance of a given nt::new_type + * + * @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 + auto constexpr + operator==(BaseType const & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_equality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs == rhs.decay(); + } + /** * @brief Compare two objects for non-equality * @@ -244,6 +275,37 @@ namespace nt return lhs.decay() != rhs.decay(); } + /** + * @brief Compare an instance of a given nt::new_type with an object of its base type + * + * @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 + auto constexpr operator!=(new_type const & lhs, + BaseType const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs.decay() != rhs; + } + + /** + * @brief Compare an instance of the base type with an instance of a given nt::new_type + * + * @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 + auto constexpr + operator!=(BaseType const & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs != rhs.decay(); + } + /// @section Relational operators /** diff --git a/test/src/equality_comparison_suite.cpp b/test/src/equality_comparison_suite.cpp index 64c7521..0789ae8 100644 --- a/test/src/equality_comparison_suite.cpp +++ b/test/src/equality_comparison_suite.cpp @@ -16,7 +16,7 @@ inline namespace basic_equality_comparsion_tests auto two_instances_of_the_same_new__type_with_the_same_value_compare_equal() -> void { - using type_alias = nt::new_type; + using type_alias = nt::new_type; auto constexpr lhs = type_alias{42}; auto constexpr rhs = type_alias{42}; @@ -26,7 +26,7 @@ inline namespace basic_equality_comparsion_tests auto two_instances_of_the_same_new__type_with_the_same_value_do_not_compare_not_equal() -> void { - using type_alias = nt::new_type; + using type_alias = nt::new_type; auto constexpr lhs = type_alias{42}; auto constexpr rhs = type_alias{42}; @@ -36,7 +36,7 @@ inline namespace basic_equality_comparsion_tests auto two_instances_of_the_same_new__type_with_differing_values_do_compare_not_equal() -> void { - using type_alias = nt::new_type; + using type_alias = nt::new_type; auto constexpr lhs = type_alias{42}; auto constexpr rhs = type_alias{43}; @@ -46,7 +46,7 @@ inline namespace basic_equality_comparsion_tests auto two_instances_of_the_same_new__type_with_differing_values_do_not_compare_equal() -> void { - using type_alias = nt::new_type; + using type_alias = nt::new_type; auto constexpr lhs = type_alias{42}; auto constexpr rhs = type_alias{43}; @@ -61,7 +61,7 @@ inline namespace equality_comparsion_noexcept_tests auto equality_comparison_on_a_new__type_is_noexcept_if_the_base_type_is_noexcept_comparable() -> void { - using type_alias = nt::new_type; + using type_alias = nt::new_type; static_assert(noexcept(std::declval() == std::declval()), "Sanity Check"); ASSERT(noexcept(std::declval() == std::declval())); } @@ -76,14 +76,14 @@ inline namespace equality_comparsion_noexcept_tests } }; - using type_alias = nt::new_type; + using type_alias = nt::new_type; static_assert(!noexcept(std::declval() == std::declval()), "Sanity Check"); ASSERT(!noexcept(std::declval() == std::declval())); } auto inequality_comparison_on_a_new__type_is_noexcept_if_the_base_type_is_noexcept_comparable() -> void { - using type_alias = nt::new_type; + using type_alias = nt::new_type; static_assert(noexcept(std::declval() != std::declval()), "Sanity Check"); ASSERT(noexcept(std::declval() != std::declval())); } @@ -98,7 +98,7 @@ inline namespace equality_comparsion_noexcept_tests } }; - using type_alias = nt::new_type; + using type_alias = nt::new_type; static_assert(!noexcept(std::declval() != std::declval()), "Sanity Check"); ASSERT(!noexcept(std::declval() != std::declval())); } @@ -110,18 +110,55 @@ inline namespace equality_comparison_return_type_tests auto equality_comparsion_of_two_new__type_instances_returns_bool() -> void { - using type_alias = nt::new_type; + using type_alias = nt::new_type; ASSERT((std::is_same_v() == std::declval())>)); } auto inequality_comparsion_of_two_new__type_instances_returns_bool() -> void { - using type_alias = nt::new_type; + using type_alias = nt::new_type; ASSERT((std::is_same_v() != std::declval())>)); } } // namespace equality_comparison_return_type_tests +inline namespace base_type_equality_comparison_tests +{ + + auto an_instance_of_a_new__type_compares_equal_to_an_instance_of_its_base_type_with_the_same_value() -> void + { + using type_alias = nt::new_type; + auto lhs = type_alias{42}; + auto rhs = 42; + ASSERT_EQUAL(lhs, rhs); + } + + auto an_instance_of_the_base_type_of_a_new__type_compares_equal_to_an_instance_of_the_new__type_with_the_same_value() -> void + { + using type_alias = nt::new_type; + auto lhs = 42; + auto rhs = type_alias{42}; + ASSERT_EQUAL(lhs, rhs); + } + + auto an_instance_of_a_new__type_compares_not_equal_to_an_instance_of_its_base_type_with_a_differing_value() -> void + { + using type_alias = nt::new_type; + auto lhs = type_alias{42}; + auto rhs = 43; + ASSERT(lhs != rhs); + } + + auto an_instance_of_the_base_type_of_a_new__type_compares_not_equal_to_an_instance_of_the_new__type_with_a_differing_value() -> void + { + using type_alias = nt::new_type; + auto lhs = 43; + auto rhs = type_alias{42}; + ASSERT(lhs != rhs); + } + +} // namespace base_type_equality_comparison_tests + auto equality_comparison_suite() -> std::pair { return {{ @@ -140,6 +177,12 @@ auto equality_comparison_suite() -> std::pair // Equality Comparison Return Type Tests KAWAII(equality_comparsion_of_two_new__type_instances_returns_bool), KAWAII(inequality_comparsion_of_two_new__type_instances_returns_bool), + + // Base-type Equality Comparison Tests + KAWAII(an_instance_of_a_new__type_compares_equal_to_an_instance_of_its_base_type_with_the_same_value), + KAWAII(an_instance_of_the_base_type_of_a_new__type_compares_equal_to_an_instance_of_the_new__type_with_the_same_value), + KAWAII(an_instance_of_a_new__type_compares_not_equal_to_an_instance_of_its_base_type_with_a_differing_value), + KAWAII(an_instance_of_the_base_type_of_a_new__type_compares_not_equal_to_an_instance_of_the_new__type_with_a_differing_value), }, "Equality Comparison Tests"}; } \ No newline at end of file -- cgit v1.2.3