From bab7acfe1bbb98022060234a38c731255483254e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Tue, 19 Sep 2023 12:31:05 -0400 Subject: [PATCH] feat!: add number concepts --- example/include/ranged_representation.h | 31 +- example/measurement.cpp | 24 +- .../mp-units/bits/external/type_list.h | 1 + src/core/include/mp-units/bits/fwd.h | 34 ++ .../include/mp-units/bits/quantity_concepts.h | 4 +- .../mp-units/bits/quantity_point_concepts.h | 1 + .../include/mp-units/customization_points.h | 1 + src/core/include/mp-units/numbers.h | 294 ++++++++++++++++++ src/core/include/mp-units/quantity.h | 106 ++----- src/core/include/mp-units/quantity_point.h | 40 ++- src/core/include/mp-units/reference.h | 4 +- src/utility/include/mp-units/math.h | 2 +- .../unit_test/runtime/linear_algebra_test.cpp | 5 + .../static/custom_rep_test_min_impl.cpp | 23 +- test/unit_test/static/quantity_point_test.cpp | 2 + test/unit_test/static/quantity_test.cpp | 4 + 16 files changed, 469 insertions(+), 107 deletions(-) create mode 100644 src/core/include/mp-units/bits/fwd.h create mode 100644 src/core/include/mp-units/numbers.h diff --git a/example/include/ranged_representation.h b/example/include/ranged_representation.h index 82f518468..103ad4233 100644 --- a/example/include/ranged_representation.h +++ b/example/include/ranged_representation.h @@ -38,7 +38,7 @@ template) auto Max> using is_in_range_t = decltype(is_in_range); -template) auto Min, +template) auto Min, MP_UNITS_CONSTRAINED_NTTP_WORKAROUND(std::convertible_to) auto Max> class ranged_representation : public validated_type> { public: @@ -50,15 +50,44 @@ class ranged_representation : public validated_typevalue()); } + + friend constexpr ranged_representation operator-(const ranged_representation& lhs, const ranged_representation& rhs) + { + return ranged_representation(lhs.value() - rhs.value()); + } + + constexpr ranged_representation& operator+=(ranged_representation that) + { + this->value() += that.value(); + gsl_Expects(validate(this->value())); + return *this; + } + constexpr ranged_representation& operator-=(ranged_representation that) + { + this->value() -= that.value(); + gsl_Expects(validate(this->value())); + return *this; + } + constexpr ranged_representation& operator*=(T rhs) + { + this->value() *= rhs; + gsl_Expects(validate(this->value())); + return *this; + } }; template inline constexpr bool mp_units::is_scalar> = mp_units::is_scalar; +template +struct mp_units::number_scalar> : std::type_identity {}; + template inline constexpr bool mp_units::treat_as_floating_point> = mp_units::treat_as_floating_point; +static_assert(mp_units::vector_space>); + template struct MP_UNITS_STD_FMT::formatter> : formatter { template diff --git a/example/measurement.cpp b/example/measurement.cpp index b67416273..617266679 100644 --- a/example/measurement.cpp +++ b/example/measurement.cpp @@ -30,7 +30,7 @@ namespace { -template +template class measurement { public: using value_type = T; @@ -65,6 +65,18 @@ class measurement { return measurement(lhs.value() - rhs.value(), hypot(lhs.uncertainty(), rhs.uncertainty())); } + constexpr measurement& operator+=(measurement that) + { + value_ = *this + that; + return *this; + } + + constexpr measurement& operator-=(measurement that) + { + value_ = *this - that; + return *this; + } + [[nodiscard]] friend constexpr measurement operator*(const measurement& lhs, const measurement& rhs) { const auto val = lhs.value() * rhs.value(); @@ -78,6 +90,12 @@ class measurement { return measurement(val, val * lhs.relative_uncertainty()); } + constexpr measurement& operator*=(const value_type& value) + { + value_ = *this * value; + return *this; + } + [[nodiscard]] friend constexpr measurement operator*(const value_type& value, const measurement& rhs) { const auto val = rhs.value() * value; @@ -125,7 +143,11 @@ inline constexpr bool mp_units::is_scalar> = true; template inline constexpr bool mp_units::is_vector> = true; +template +struct mp_units::number_scalar> : std::type_identity {}; + static_assert(mp_units::RepresentationOf, mp_units::quantity_character::scalar>); +static_assert(mp_units::vector_space>); namespace { diff --git a/src/core/include/mp-units/bits/external/type_list.h b/src/core/include/mp-units/bits/external/type_list.h index 5369ce18d..80b66e060 100644 --- a/src/core/include/mp-units/bits/external/type_list.h +++ b/src/core/include/mp-units/bits/external/type_list.h @@ -24,6 +24,7 @@ #include // IWYU pragma: keep #include +#include #include MP_UNITS_DIAGNOSTIC_PUSH diff --git a/src/core/include/mp-units/bits/fwd.h b/src/core/include/mp-units/bits/fwd.h new file mode 100644 index 000000000..22ac3247a --- /dev/null +++ b/src/core/include/mp-units/bits/fwd.h @@ -0,0 +1,34 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +namespace mp_units { + +template Rep> + requires vector_space +class quantity; + +} // namespace mp_units diff --git a/src/core/include/mp-units/bits/quantity_concepts.h b/src/core/include/mp-units/bits/quantity_concepts.h index 437d64e30..f9bdaeb0b 100644 --- a/src/core/include/mp-units/bits/quantity_concepts.h +++ b/src/core/include/mp-units/bits/quantity_concepts.h @@ -22,6 +22,7 @@ #pragma once +#include #include #include #include @@ -29,9 +30,6 @@ namespace mp_units { -template Rep> -class quantity; - #if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17 template #else diff --git a/src/core/include/mp-units/bits/quantity_point_concepts.h b/src/core/include/mp-units/bits/quantity_point_concepts.h index 90a9e85be..f0cebea18 100644 --- a/src/core/include/mp-units/bits/quantity_point_concepts.h +++ b/src/core/include/mp-units/bits/quantity_point_concepts.h @@ -107,6 +107,7 @@ concept PointOriginFor = PointOrigin && QuantitySpecOf auto PO, RepresentationOf Rep> + requires vector_space class quantity_point; #if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17 diff --git a/src/core/include/mp-units/customization_points.h b/src/core/include/mp-units/customization_points.h index e4c169169..0ddd4eea7 100644 --- a/src/core/include/mp-units/customization_points.h +++ b/src/core/include/mp-units/customization_points.h @@ -24,6 +24,7 @@ #include #include +#include #include #include diff --git a/src/core/include/mp-units/numbers.h b/src/core/include/mp-units/numbers.h new file mode 100644 index 000000000..7b72b4831 --- /dev/null +++ b/src/core/include/mp-units/numbers.h @@ -0,0 +1,294 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include + +namespace mp_units { + +template +struct number_scalar; + +namespace detail { + +template +struct inferred_number_zero {}; +template +struct inferred_number_one {}; + +} // namespace detail + +template +using number_difference_t = decltype(std::declval() - std::declval()); +template +using number_scalar_t = number_scalar::type; + +template +concept is_inferred_number = std::regular>; + +template +struct is_number : std::bool_constant> {}; +template +struct is_complex_number : std::false_type {}; +template +struct number_zero : detail::inferred_number_zero {}; +template +struct number_one : detail::inferred_number_one {}; +template +struct number_scalar {}; + +template +constexpr bool is_number_v = is_number::value; +template +constexpr bool is_complex_number_v = is_complex_number::value; + +template +constexpr T number_zero_v = number_zero::value; +template +constexpr T number_one_v = number_one::value; + +template +concept number = is_number_v && std::regular; + +template +concept ordered_number = number && std::totally_ordered; + +template +concept number_line = // clang-format off + ordered_number && + requires(T& v) { + number_one_v>; + { ++v } -> std::same_as; + { --v } -> std::same_as; + { v-- } -> std::same_as; + { v-- } -> std::same_as; + }; // clang-format on + +namespace detail { + +template +concept addition_with = // clang-format off + number && + number && + requires( const T & c, const U & d) { + { c + d } -> std::common_with; + { d + c } -> std::common_with; + }; // clang-format on + +template +concept compound_addition_with = // clang-format off + addition_with && + requires(T& l, const U & d) { + { l += d } -> std::same_as; + }; // clang-format on + +template +concept subtraction_with = // clang-format off + addition_with && + requires( const T & c, const U & d) { + { c - d } -> std::common_with; + }; // clang-format on + +template +concept compound_subtraction_with = // clang-format off + subtraction_with && + compound_addition_with && + requires(T& l, const U & d) { + { l -= d } -> std::same_as; + }; // clang-format on + +template +concept multiplication_with = // clang-format off + number && + number && + number && + requires( const T & c, const U & u) { + { (c * u) } -> std::common_with; + }; // clang-format on + +template +concept compound_multiplication_with = // clang-format off + multiplication_with && + requires(T& l, const U & u) { + { l *= u } -> std::same_as; + }; // clang-format on + +template +concept division_with = // clang-format off + multiplication_with && + multiplication_with && + requires( const T & c, const U & u) { + { c / u } -> std::common_with; + }; // clang-format on + +template +concept compound_division_with = // clang-format off + division_with && + compound_multiplication_with && + requires(T& l, const U & u) { + { l /= u } -> std::same_as; + }; // clang-format on + +} // namespace detail + +template +concept modulo_with = // clang-format off + number && + number && + requires( const T & c, const U & u) { + { (c % u) } -> std::common_with; + }; // clang-format on + +template +concept compound_modulo_with = // clang-format off + modulo_with && + requires(T& l, const U & u) { + { l %= u } -> std::same_as; + }; // clang-format on + +template +concept modulus_for = modulo_with; +template +concept compound_modulus_for = compound_modulo_with; + +template +concept negative = // clang-format off + detail::compound_addition_with && + requires( const T & c) { + number_zero_v; + { -c } -> std::common_with; + }; // clang-format on + +template +concept set_with_inverse = // clang-format off + detail::compound_multiplication_with && + requires( const T & c) { + { number_one_v / c } -> std::common_with; + }; // clang-format on + +template +concept point_space_for = detail::subtraction_with && negative && std::common_with, U>; +template +concept compound_point_space_for = point_space_for && detail::compound_subtraction_with; +template +concept point_space = compound_point_space_for>; + +template +concept vector_space_for = point_space_for; +template +concept compound_vector_space_for = compound_point_space_for; + +namespace detail { + +template +concept weak_scalar = std::common_with> && point_space && negative; + +template +concept scales_with = + std::common_with> && weak_scalar && multiplication_with && set_with_inverse; +template +concept compound_scales_with = scales_with && detail::compound_multiplication_with; + +} // namespace detail + +template +concept scalar_for = detail::scales_with; +template +concept field_for = scalar_for && detail::division_with; +template +concept compound_scalar_for = detail::compound_scales_with; +template +concept compound_field_for = compound_scalar_for && detail::compound_division_with; + +template +concept vector_space = point_space && detail::compound_scales_with>; +template +concept f_vector_space = vector_space && detail::compound_division_with>; + +template +concept field_number = f_vector_space && detail::compound_scales_with; + +template +concept field_number_line = field_number && number_line; + +template +concept scalar_number = field_number && (field_number_line || is_complex_number_v); + +template +struct is_number : is_number {}; +template +struct is_number> : std::true_type {}; +#if __cpp_lib_chrono >= 201803 +template<> +struct is_number : std::true_type {}; +template<> +struct is_number : std::true_type {}; +template<> +struct is_number : std::true_type {}; +template<> +struct is_number : std::true_type {}; +template<> +struct is_number : std::true_type {}; +#endif + +template +struct is_complex_number : is_complex_number {}; +template +struct is_complex_number> : std::true_type {}; + +namespace detail { + +template +concept inferable_identities = std::common_with> && std::constructible_from; + +template +struct inferred_number_zero { + auto static constexpr value = T(0); +}; +template +struct inferred_number_one { + auto static constexpr value = T(1); +}; + +} // namespace detail + +template +struct number_zero : number_zero {}; +template +struct number_one : number_one {}; + +template +struct number_scalar : number_scalar {}; +template +struct number_scalar : std::type_identity {}; +template +struct number_scalar : std::type_identity {}; +template +struct number_scalar> : std::type_identity {}; +template +struct number_scalar> : std::type_identity {}; + +} // namespace mp_units diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index e1e989cd5..48a4ea9ad 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -83,6 +83,7 @@ using common_quantity_for = quantity Rep = double> + requires vector_space class quantity { public: Rep numerical_value_; // needs to be public for a structural type @@ -201,92 +202,60 @@ class quantity { } [[nodiscard]] constexpr Quantity auto operator-() const - requires requires(rep v) { - { - -v - } -> std::common_with; - } + requires negative { return make_quantity(-numerical_value_); } template - friend constexpr decltype(auto) operator++(Q&& q) - requires std::derived_from, quantity> && requires(rep v) { - { - ++v - } -> std::same_as; - } + friend constexpr decltype(auto) operator++(Q && q) + requires std::derived_from, quantity> && number_line { ++q.numerical_value_; return std::forward(q); } [[nodiscard]] constexpr Quantity auto operator++(int) - requires requires(rep v) { - { - v++ - } -> std::common_with; - } + requires number_line { return make_quantity(numerical_value_++); } template - friend constexpr decltype(auto) operator--(Q&& q) - requires std::derived_from, quantity> && requires(rep v) { - { - --v - } -> std::same_as; - } + friend constexpr decltype(auto) operator--(Q && q) + requires std::derived_from, quantity> && number_line { --q.numerical_value_; return std::forward(q); } [[nodiscard]] constexpr Quantity auto operator--(int) - requires requires(rep v) { - { - v-- - } -> std::common_with; - } + requires number_line { return make_quantity(numerical_value_--); } // compound assignment operators template - requires std::derived_from, quantity> && requires(rep a, rep b) { - { - a += b - } -> std::same_as; - } - friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs) + requires std::derived_from, quantity> + friend constexpr decltype(auto) operator+=(Q && lhs, const quantity & rhs) { lhs.numerical_value_ += rhs.numerical_value_; return std::forward(lhs); } template - requires std::derived_from, quantity> && requires(rep a, rep b) { - { - a -= b - } -> std::same_as; - } - friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs) + requires std::derived_from, quantity> + friend constexpr decltype(auto) operator-=(Q && lhs, const quantity & rhs) { lhs.numerical_value_ -= rhs.numerical_value_; return std::forward(lhs); } template - requires std::derived_from, quantity> && (!treat_as_floating_point) && - requires(rep a, rep b) { - { - a %= b - } -> std::same_as; - } - friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs) + requires std::derived_from, quantity> && + (!treat_as_floating_point) && compound_modulus_for + friend constexpr decltype(auto) operator%=(Q && lhs, const quantity & rhs) { gsl_ExpectsAudit(rhs != zero()); @@ -294,40 +263,26 @@ class quantity { return std::forward(lhs); } - template - requires std::derived_from, quantity> && (!Quantity) && - requires(rep a, const Value b) { - { - a *= b - } -> std::same_as; - } - friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v) + template Value> + requires std::derived_from, quantity> + friend constexpr decltype(auto) operator*=(Q && lhs, const Value & v) { lhs.numerical_value_ *= v; return std::forward(lhs); } template Q2> - requires std::derived_from, quantity> && (Q2::unit == ::mp_units::one) && - requires(rep a, const typename Q2::rep b) { - { - a *= b - } -> std::same_as; - } - friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs) + requires std::derived_from, quantity> && + (Q2::unit == ::mp_units::one) && compound_scalar_for + friend constexpr decltype(auto) operator*=(Q1 && lhs, const Q2 & rhs) { lhs.numerical_value_ *= rhs.numerical_value_; return std::forward(lhs); } - template - requires std::derived_from, quantity> && (!Quantity) && - requires(rep a, const Value b) { - { - a /= b - } -> std::same_as; - } - friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v) + template Value> + requires std::derived_from, quantity> + friend constexpr decltype(auto) operator/=(Q && lhs, const Value & v) { gsl_ExpectsAudit(v != quantity_values::zero()); lhs.numerical_value_ /= v; @@ -335,13 +290,9 @@ class quantity { } template Q2> - requires std::derived_from, quantity> && (Q2::unit == ::mp_units::one) && - requires(rep a, const typename Q2::rep b) { - { - a /= b - } -> std::same_as; - } - friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs) + requires std::derived_from, quantity> && + (Q2::unit == ::mp_units::one) && compound_field_for + friend constexpr decltype(auto) operator/=(Q1 && lhs, const Q2 & rhs) { gsl_ExpectsAudit(rhs != rhs.zero()); lhs.numerical_value_ /= rhs.numerical_value_; @@ -472,6 +423,9 @@ template return quantity>(std::forward(v)); } +template +struct number_scalar : number_scalar {}; + } // namespace mp_units namespace std { diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 3a8dd8bd1..2d9de72f7 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -70,6 +70,7 @@ namespace detail { */ template auto PO, RepresentationOf Rep = double> + requires vector_space class quantity_point { public: // member types and values @@ -184,47 +185,45 @@ class quantity_point { // member unary operators template - friend constexpr decltype(auto) operator++(QP&& qp) - requires std::derived_from, quantity_point> && requires { ++qp.quantity_from_origin_; } + friend constexpr decltype(auto) operator++(QP && qp) + requires std::derived_from, quantity_point> && number_line { ++qp.quantity_from_origin_; return std::forward(qp); } [[nodiscard]] constexpr quantity_point operator++(int) - requires requires { quantity_from_origin_++; } + requires number_line { return quantity_point(quantity_from_origin_++); } template - friend constexpr decltype(auto) operator--(QP&& qp) - requires std::derived_from, quantity_point> && requires { --qp.quantity_from_origin_; } + friend constexpr decltype(auto) operator--(QP && qp) + requires std::derived_from, quantity_point> && number_line { --qp.quantity_from_origin_; return std::forward(qp); } [[nodiscard]] constexpr quantity_point operator--(int) - requires requires { quantity_from_origin_--; } + requires number_line { return quantity_point(quantity_from_origin_--); } // compound assignment operators template - requires std::derived_from, quantity_point> && - requires(quantity_type q) { quantity_from_origin_ += q; } - friend constexpr decltype(auto) operator+=(QP&& qp, const quantity_type& q) + requires std::derived_from, quantity_point> + friend constexpr decltype(auto) operator+=(QP && qp, const quantity_type & q) { qp.quantity_from_origin_ += q; return std::forward(qp); } template - requires std::derived_from, quantity_point> && - requires(quantity_type q) { quantity_from_origin_ -= q; } - friend constexpr decltype(auto) operator-=(QP&& qp, const quantity_type& q) + requires std::derived_from, quantity_point> + friend constexpr decltype(auto) operator-=(QP && qp, const quantity_type & q) { qp.quantity_from_origin_ -= q; return std::forward(qp); @@ -253,22 +252,20 @@ explicit quantity_point(QP) -> quantity_point::reference, quantity_point_like_traits::point_origin, typename quantity_point_like_traits::rep>; -template +template Rep2> // TODO simplify when gcc catches up requires ReferenceOf, PO1.quantity_spec> [[nodiscard]] constexpr QuantityPoint auto operator+(const quantity_point& qp, const quantity& q) - requires requires { qp.quantity_ref_from(PO1) + q; } { return make_quantity_point(qp.quantity_ref_from(PO1) + q); } -template +template Rep1> // TODO simplify when gcc catches up requires ReferenceOf, PO2.quantity_spec> [[nodiscard]] constexpr QuantityPoint auto operator+(const quantity& q, const quantity_point& qp) - requires requires { q + qp.quantity_ref_from(PO2); } { return qp + q; } @@ -287,12 +284,11 @@ template return po + std::forward(q); } -template +template Rep2> // TODO simplify when gcc catches up requires ReferenceOf, PO1.quantity_spec> [[nodiscard]] constexpr QuantityPoint auto operator-(const quantity_point& qp, const quantity& q) - requires requires { qp.quantity_ref_from(PO1) - q; } { return make_quantity_point(qp.quantity_ref_from(PO1) - q); } @@ -300,15 +296,14 @@ template template requires ReferenceOf, PO::quantity_spec> [[nodiscard]] constexpr QuantityPoint auto operator-(PO po, const Q& q) - requires requires { -q; } { return po + (-q); } template QP2> +// TODO consider constraining it for both branches + requires vector_space_for [[nodiscard]] constexpr Quantity auto operator-(const QP1& lhs, const QP2& rhs) - // TODO consider constraining it for both branches - requires requires { lhs.quantity_ref_from(QP1::point_origin) - rhs.quantity_ref_from(QP2::point_origin); } { if constexpr (is_same_v, std::remove_const_t>) @@ -398,4 +393,7 @@ template return quantity_point(std::forward(q)); } +template +struct is_number : std::true_type {}; + } // namespace mp_units diff --git a/src/core/include/mp-units/reference.h b/src/core/include/mp-units/reference.h index 032c4192a..bf896e502 100644 --- a/src/core/include/mp-units/reference.h +++ b/src/core/include/mp-units/reference.h @@ -22,6 +22,7 @@ #pragma once +#include #include #include #include @@ -155,9 +156,6 @@ struct reference { } }; -template Rep> -class quantity; - template [[nodiscard]] constexpr quantity> operator*(Rep&& lhs, R) { diff --git a/src/utility/include/mp-units/math.h b/src/utility/include/mp-units/math.h index 29254672e..635ab496e 100644 --- a/src/utility/include/mp-units/math.h +++ b/src/utility/include/mp-units/math.h @@ -274,7 +274,7 @@ template /** * @brief Computes the inverse of a quantity in a provided unit */ -template +template [[nodiscard]] constexpr QuantityOf auto inverse(const quantity& q) requires requires { quantity_values::one(); diff --git a/test/unit_test/runtime/linear_algebra_test.cpp b/test/unit_test/runtime/linear_algebra_test.cpp index ad9fb31f4..b0be693b5 100644 --- a/test/unit_test/runtime/linear_algebra_test.cpp +++ b/test/unit_test/runtime/linear_algebra_test.cpp @@ -34,12 +34,17 @@ template using vector = STD_LA::fixed_size_column_vector; +static_assert(mp_units::vector_space{3, 2, 1})>); + template inline constexpr bool mp_units::treat_as_floating_point> = mp_units::treat_as_floating_point; template inline constexpr bool mp_units::is_vector> = true; +template +constexpr bool mp_units::is_number_v> = mp_units::is_number_v; + template std::ostream& operator<<(std::ostream& os, const vector& v) { diff --git a/test/unit_test/static/custom_rep_test_min_impl.cpp b/test/unit_test/static/custom_rep_test_min_impl.cpp index 7d18effd7..a137437da 100644 --- a/test/unit_test/static/custom_rep_test_min_impl.cpp +++ b/test/unit_test/static/custom_rep_test_min_impl.cpp @@ -32,7 +32,7 @@ namespace { * * @tparam T element type */ -template +template class min_impl { T value_; public: @@ -45,6 +45,22 @@ class min_impl { { } constexpr explicit(false) operator T() const noexcept { return value_; } + + constexpr min_impl& operator+=(min_impl that) + { + value_ += that.value_; + return *this; + } + constexpr min_impl& operator-=(min_impl that) + { + value_ -= that.value_; + return *this; + } + constexpr min_impl& operator*=(T rhs) + { + value_ *= rhs; + return *this; + } }; } // namespace @@ -52,6 +68,9 @@ class min_impl { template inline constexpr bool mp_units::is_scalar> = true; +template +struct mp_units::number_scalar> : std::type_identity {}; + template struct std::common_type, min_impl> : std::type_identity>> {}; template @@ -65,6 +84,8 @@ using namespace mp_units; static_assert(Representation>); static_assert(Representation>); +static_assert(vector_space>); +static_assert(vector_space>); // construction from a value is not allowed static_assert(!std::constructible_from>, min_impl>); diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index feb633d65..e71003690 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -130,6 +130,8 @@ static_assert(std::regular>); static_assert(std::three_way_comparable>); +static_assert(point_space>); + ////////////////// // member values diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 77091cb73..dd78b975e 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -85,6 +85,10 @@ static_assert(std::regular>); static_assert(std::three_way_comparable>); +static_assert(f_vector_space>); +static_assert(!scalar_number>, + "`std::common_with, double>` is `false`."); + ////////////////// // member values