From f2e63fdeb1fe0b143876f5e16e342283834c7abd Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 9 Nov 2022 18:39:51 -1000 Subject: [PATCH] refactor: `std::common_type` usage replaced with dedicated functions for units, dimensions, and references --- src/core/include/units/dimension.h | 29 +++++-------- src/core/include/units/quantity.h | 25 +++++------ src/core/include/units/reference.h | 27 ++++++------ src/core/include/units/unit.h | 17 ++------ test/unit_test/static/dimension_test.cpp | 19 ++++----- test/unit_test/static/unit_test.cpp | 54 ++++++++++++------------ 6 files changed, 74 insertions(+), 97 deletions(-) diff --git a/src/core/include/units/dimension.h b/src/core/include/units/dimension.h index 22f3aeac..546d3067 100644 --- a/src/core/include/units/dimension.h +++ b/src/core/include/units/dimension.h @@ -386,31 +386,22 @@ template requires requires { detail::get_dimension_for(U); } && (interconvertible(Dim, detail::get_dimension_for(U))) inline constexpr bool is_valid_unit_for_dimension = true; -} // namespace detail +template +[[nodiscard]] consteval auto common_dimension(D1 d1, D2 d2) + requires(interconvertible(d1, d2)) +{ + if constexpr (std::derived_from) + return d1; + else + return d2; +} +} // namespace detail // TODO consider adding the support for text output of the dimensional equation } // namespace units -namespace std { - -/** - * @brief Partial specialization of `std::common_type` for dimensions - * - * Defined only for convertible types and returns the most derived/specific dimension type of - * the two provided. - */ -template - requires(units::interconvertible(D1{}, D2{})) -struct common_type { - using type = ::units::conditional, std::remove_const_t>, - std::remove_const_t, std::remove_const_t>; -}; - -} // namespace std - - #ifdef __cpp_explicit_this_parameter #define BASE_DIMENSION(name, symbol) \ diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index 1d4c65b4..ad21ef4b 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -474,8 +474,8 @@ template quantity_value_for_, typename Q1::rep, typename Q2::rep> [[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs) { - using ref = std::common_type_t; - using ret = quantity; + constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference); + using ret = quantity; return ret(ret(lhs).number() + ret(rhs).number()); } @@ -484,8 +484,8 @@ template quantity_value_for_, typename Q1::rep, typename Q2::rep> [[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs) { - using ref = std::common_type_t; - using ret = quantity; + constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference); + using ret = quantity; return ret(ret(lhs).number() - ret(rhs).number()); } @@ -521,8 +521,8 @@ template std::three_way_comparable_with [[nodiscard]] constexpr auto operator<=>(const Q1& lhs, const Q2& rhs) { - using ref = std::common_type_t; - return quantity_cast(lhs).number() <=> quantity_cast(rhs).number(); + constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference); + return quantity_cast(lhs).number() <=> quantity_cast(rhs).number(); } template @@ -530,8 +530,8 @@ template std::equality_comparable_with [[nodiscard]] constexpr bool operator==(const Q1& lhs, const Q2& rhs) { - using ref = std::common_type_t; - return quantity_cast(lhs).number() == quantity_cast(rhs).number(); + constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference); + return quantity_cast(lhs).number() == quantity_cast(rhs).number(); } } // namespace units @@ -540,14 +540,15 @@ namespace std { template requires requires { - typename common_type_t, remove_const_t>; + { + units::detail::common_reference(Q1::reference, Q2::reference) + } -> units::Reference; typename common_type_t; } struct common_type { -private: - using ref = common_type_t, remove_const_t>; public: - using type = units::quantity>; + using type = units::quantity>; }; } // namespace std diff --git a/src/core/include/units/reference.h b/src/core/include/units/reference.h index d50c32e5..63dbdcfa 100644 --- a/src/core/include/units/reference.h +++ b/src/core/include/units/reference.h @@ -107,21 +107,20 @@ template return interconvertible(R1::dimension, R2::dimension) && interconvertible(R1::unit, R2::unit); } -} // namespace units +namespace detail { -namespace std { - -template +[[nodiscard]] consteval auto common_reference(Reference auto r1, Reference auto r2) requires requires { - typename common_type_t, remove_const_t>; - typename common_type_t, remove_const_t>; + { + common_dimension(r1.dimension, r2.dimension) + } -> Dimension; + { + common_unit(r1.unit, r2.unit) + } -> Unit; } -struct common_type { -private: - using dim = common_type_t, remove_const_t>; - using unit = common_type_t, remove_const_t>; -public: - using type = units::reference; -}; +{ + return reference{}; +} -} // namespace std +} // namespace detail +} // namespace units diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index 6001a8ec..a2fe3d19 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -796,9 +796,9 @@ template namespace detail { - -template -[[nodiscard]] consteval auto common_type_impl(const U1 u1, const U2 u2) +template +[[nodiscard]] consteval auto common_unit(U1 u1, U2 u2) + requires(interconvertible(u1, u2)) { if constexpr (U1{} == U2{}) { if constexpr (std::derived_from) @@ -821,15 +821,4 @@ template } } // namespace detail - } // namespace units - -namespace std { - -template - requires(units::interconvertible(U1{}, U2{})) -struct common_type { - using type = std::remove_const_t; -}; - -} // namespace std diff --git a/test/unit_test/static/dimension_test.cpp b/test/unit_test/static/dimension_test.cpp index c4e46edf..62e3be17 100644 --- a/test/unit_test/static/dimension_test.cpp +++ b/test/unit_test/static/dimension_test.cpp @@ -174,15 +174,15 @@ static_assert(1 / time != frequency); static_assert(interconvertible(1 / time, frequency)); static_assert(1 / frequency == time); static_assert(frequency * time == dimension_one); -static_assert(std::is_same_v, frequency_>); -static_assert(std::is_same_v, frequency_>); +static_assert(is_of_type); +static_assert(is_of_type); static_assert(length * length != area); static_assert(interconvertible(length * length, area)); static_assert(length * length != volume); static_assert(area / length == length); -static_assert(std::is_same_v, area_>); -static_assert(std::is_same_v, area_>); +static_assert(is_of_type); +static_assert(is_of_type); static_assert(length * length * length != volume); static_assert(area * length != volume); @@ -197,10 +197,9 @@ static_assert(length * time != speed); static_assert(length / time / time != speed); static_assert(length / speed == time); static_assert(speed * time == length); -static_assert(std::is_same_v, speed_>); -static_assert(std::is_same_v, speed_>); -static_assert( - std::is_same_v, decltype(length / time)>); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert(is_of_type); static_assert(length / time / time != acceleration); static_assert(length / (time * time) != acceleration); @@ -213,8 +212,8 @@ static_assert(acceleration / speed != frequency); // comparison of convertible named dimensions static_assert(velocity != speed); static_assert(interconvertible(speed, velocity)); -static_assert(std::is_same_v, velocity_>); -static_assert(std::is_same_v, velocity_>); +static_assert(is_of_type); +static_assert(is_of_type); // comparison of convertible unnamed dimensions static_assert(is_of_type>>>); diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index cb1c2ddd..3b0427ed 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -469,35 +469,33 @@ static_assert( is_of_type(mag<3600>* second), scaled_unit * mag<3600>, derived_unit>>>); // common_type -static_assert(std::is_same_v, gram_>); -static_assert(std::is_same_v, kilogram_>); -static_assert(std::is_same_v), decltype(kilogram)>, kilogram_>); -static_assert(std::is_same_v)>, kilogram_>); -static_assert(std::is_same_v * gram), decltype(kilogram)>, kilogram_>); -static_assert(std::is_same_v * gram)>, kilogram_>); -static_assert(std::is_same_v, hertz_>); -static_assert(std::is_same_v, hertz_>); -static_assert(std::is_same_v, gram_>); -static_assert(std::is_same_v, gram_>); -static_assert(std::is_same_v, second_>); -static_assert(std::is_same_v, second_>); -static_assert(std::is_same_v, minute_>); -static_assert(std::is_same_v, minute_>); -static_assert(std::is_same_v), decltype(si::milli)>, - std::remove_const_t)>>); -static_assert(std::is_same_v), decltype(si::kilo)>, - std::remove_const_t)>>); -static_assert(std::is_same_v, yard_>); -static_assert(std::is_same_v, yard_>); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert(is_of_type, kilogram), kilogram_>); +static_assert(is_of_type), kilogram_>); +static_assert(is_of_type* gram, kilogram), kilogram_>); +static_assert(is_of_type* gram), kilogram_>); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert(is_of_type); +static_assert( + is_of_type, si::milli), std::remove_const_t)>>); +static_assert( + is_of_type, si::kilo), std::remove_const_t)>>); +static_assert(is_of_type); +static_assert(is_of_type); // TODO The below have long/unreadable magnitude types -static_assert(std::is_same_v, - scaled_unit, derived_unit>>>); -static_assert(std::is_same_v, - scaled_unit, derived_unit>>>); -static_assert( - std::is_same_v, scaled_unit, metre_>>); -static_assert( - std::is_same_v, scaled_unit, metre_>>); +static_assert(is_of_type, derived_unit>>>); +static_assert(is_of_type, derived_unit>>>); +static_assert(is_of_type, metre_>>); +static_assert(is_of_type, metre_>>); // unit symbols #ifdef __cpp_lib_constexpr_string