From cdd90fb93be3855aad8725fc22468dfc51f7ef8c Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 30 Sep 2023 21:52:25 -0600 Subject: [PATCH 01/10] docs: `CameCase` concept identifiers FAQ added --- docs/getting_started/faq.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/getting_started/faq.md b/docs/getting_started/faq.md index dcbb2715..5baca08b 100644 --- a/docs/getting_started/faq.md +++ b/docs/getting_started/faq.md @@ -166,6 +166,30 @@ all the properties of scaled units and is consistent with the rest of the librar [the Dimensionless Quantities chapter](../users_guide/framework_basics/dimensionless_quantities.md). +## Why do the identifiers for concepts in the library use `CamelCase`? + +Initially, C++20 was meant to use `CamelCase` for all the concept identifiers. All the concepts +from the `std::ranges` library were merged with such names into the standard document draft. +Frustratingly, `CamelCase` concepts got dropped from the C++ standard at the last moment before +releasing C++20. Now, we are facing the predictable consequences of running out of names. + +As long as some concepts in the library could be easily named with a `standard_case` there are +some that are hard to distinguish from the corresponding type names, such as `Quantity`, +`QuantityPoint`, `QuantitySpec`, or `Reference`. This is why we decided to use `CamelCase` +consistently for all the concept identifiers to make it clear when we are talking about a type +or concept identifier. + +However, we are aware that this might be a temporary solution. In case the library gets +standardized, we can expect the ISO C++ Committee to bikeshed/rename all of +the concept identifiers to a `standard_case`, even if it will result in a harder to understand +code. + +!!! note + + In case you have a good idea on how to rename [existing concepts](../users_guide/framework_basics/basic_concepts.md) + to the `standard_case`, please let us know in the associated [GitHub Issue](). + + ## Why Unicode quantity symbols are used by default instead of ASCII-only characters? Both C++ and [ISO 80000](../appendix/references.md#ISO80000) are standardized by the ISO. From 335ebc9b7b42589112fe12e06c1458cb47632dad Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 30 Sep 2023 22:20:42 -0600 Subject: [PATCH 02/10] style: whitespaces in FAQ fixed to make pre-commit happy --- docs/getting_started/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting_started/faq.md b/docs/getting_started/faq.md index 5baca08b..1fef6904 100644 --- a/docs/getting_started/faq.md +++ b/docs/getting_started/faq.md @@ -187,7 +187,7 @@ code. !!! note In case you have a good idea on how to rename [existing concepts](../users_guide/framework_basics/basic_concepts.md) - to the `standard_case`, please let us know in the associated [GitHub Issue](). + to the `standard_case`, please let us know in the associated [GitHub Issue](). ## Why Unicode quantity symbols are used by default instead of ASCII-only characters? From 5a74cd66ba03752d7057c4f3b361c3ebae4e7d76 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 29 Sep 2023 12:47:02 +0200 Subject: [PATCH 03/10] feat: interoperability with other libraries redesigned --- .../framework_basics/basic_concepts.md | 46 +++++++++++++++---- .../include/mp-units/bits/quantity_concepts.h | 10 ++-- .../mp-units/bits/quantity_point_concepts.h | 16 ++++--- .../include/mp-units/customization_points.h | 40 ++++++++++++++-- src/core/include/mp-units/quantity.h | 29 ++++++++++-- src/core/include/mp-units/quantity_point.h | 35 ++++++++++++-- src/utility/include/mp-units/chrono.h | 27 +++++++++-- test/unit_test/static/chrono_test.cpp | 24 +++++----- test/unit_test/static/quantity_point_test.cpp | 2 +- 9 files changed, 182 insertions(+), 47 deletions(-) diff --git a/docs/users_guide/framework_basics/basic_concepts.md b/docs/users_guide/framework_basics/basic_concepts.md index 478ae14f..47ab42f0 100644 --- a/docs/users_guide/framework_basics/basic_concepts.md +++ b/docs/users_guide/framework_basics/basic_concepts.md @@ -427,7 +427,12 @@ for which an instantiation of `quantity_like_traits` type trait yields a valid t - Static data member `reference` that matches the [`Reference`](#Reference) concept, - `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided in `reference`, -- `value(T)` static member function returning a raw value of the quantity. +- `to_numerical_value(T)` static member function returning a raw value of the quantity packed in + either `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in + the latter case, +- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly` + or `convert_implicitly` wrapper that enables implicit conversion in the latter case. + ??? abstract "Examples" @@ -438,10 +443,20 @@ for which an instantiation of `quantity_like_traits` type trait yields a valid t struct mp_units::quantity_like_traits { static constexpr auto reference = si::second; using rep = std::chrono::seconds::rep; - [[nodiscard]] static constexpr rep value(const std::chrono::seconds& q) { return q.count(); } + + [[nodiscard]] static constexpr convert_implicitly to_numerical_value(const std::chrono::seconds& q) + { + return q.count(); + } + + [[nodiscard]] static constexpr convert_implicitly from_numerical_value(const rep& v) + { + return std::chrono::seconds(v); + } }; - quantity q(42s); + quantity q = 42s; + std::chrono::seconds dur = 42 * s; ``` @@ -454,8 +469,13 @@ for which an instantiation of `quantity_point_like_traits` type trait yields a v - Static data member `point_origin` that matches the [`PointOrigin`](#PointOrigin) concept - `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided in `reference` -- `quantity_from_origin(T)` static member function returning the `quantity` being the offset of the point - from the origin +- `to_quantity(T)` static member function returning the `quantity` being the offset of the point + from the origin packed in either `convert_explicitly` or `convert_implicitly` wrapper that enables + implicit conversion in the latter case, +- `from_quantity(quantity)` static member function returning `T` packed in either + `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in the latter + case. + ??? abstract "Examples" @@ -464,14 +484,22 @@ for which an instantiation of `quantity_point_like_traits` type trait yields a v ```cpp template struct mp_units::quantity_point_like_traits> { + using T = std::chrono::time_point; static constexpr auto reference = si::second; - static constexpr auto point_origin = chrono_point_origin; + static constexpr struct point_origin : absolute_point_origin {} point_origin{}; using rep = std::chrono::seconds::rep; - [[nodiscard]] static constexpr auto quantity_from_origin(const std::chrono::time_point& qp) + + [[nodiscard]] static constexpr convert_implicitly> to_quantity(const T& qp) { - return quantity{std::chrono::duration_cast(qp.time_since_epoch())}; + return quantity{qp.time_since_epoch()}; + } + + [[nodiscard]] static constexpr convert_implicitly from_quantity(const quantity& q) + { + return T(q); } }; - quantity_point qp(time_point_cast(std::chrono::system_clock::now())); + quantity_point qp = time_point_cast(std::chrono::system_clock::now()); + std::chrono::sys_seconds q = qp + 42 * s; ``` diff --git a/src/core/include/mp-units/bits/quantity_concepts.h b/src/core/include/mp-units/bits/quantity_concepts.h index 437d64e3..56c652b9 100644 --- a/src/core/include/mp-units/bits/quantity_concepts.h +++ b/src/core/include/mp-units/bits/quantity_concepts.h @@ -74,15 +74,19 @@ concept QuantityOf = Quantity && ReferenceOf -concept QuantityLike = requires(T q) { +concept QuantityLike = requires { quantity_like_traits::reference; requires Reference::reference)>>; typename quantity_like_traits::rep; requires RepresentationOf::rep, get_quantity_spec(quantity_like_traits::reference).character>; +} && requires(T q, typename quantity_like_traits::rep v) { { - make_quantity::reference>(quantity_like_traits::value(q)) - } -> std::same_as::reference, typename quantity_like_traits::rep>>; + quantity_like_traits::to_numerical_value(q) + } -> detail::ConversionSpecOf::rep>; + { + quantity_like_traits::from_numerical_value(v) + } -> detail::ConversionSpecOf; }; } // namespace mp_units 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 df4b1a24..b2d1091c 100644 --- a/src/core/include/mp-units/bits/quantity_point_concepts.h +++ b/src/core/include/mp-units/bits/quantity_point_concepts.h @@ -173,7 +173,7 @@ concept QuantityPointOf = * all quantity_point-specific information. */ template -concept QuantityPointLike = requires(T qp) { +concept QuantityPointLike = requires { quantity_point_like_traits::reference; requires Reference::reference)>>; quantity_point_like_traits::point_origin; @@ -181,13 +181,15 @@ concept QuantityPointLike = requires(T qp) { typename quantity_point_like_traits::rep; requires RepresentationOf::rep, get_quantity_spec(quantity_point_like_traits::reference).character>; - requires Quantity::quantity_from_origin(qp))>>; +} && requires(T qp, quantity::reference, typename quantity_point_like_traits::rep> q) { { - make_quantity_point::point_origin>( - quantity_point_like_traits::quantity_from_origin(qp)) - } - -> std::same_as::reference, quantity_point_like_traits::point_origin, - typename quantity_point_like_traits::rep>>; + quantity_point_like_traits::to_quantity(qp) + } -> detail::ConversionSpecOf< + quantity::reference, typename quantity_point_like_traits::rep>>; + + { + quantity_point_like_traits::from_quantity(q) + } -> detail::ConversionSpecOf; }; } // namespace mp_units diff --git a/src/core/include/mp-units/customization_points.h b/src/core/include/mp-units/customization_points.h index e4c16916..18f2b594 100644 --- a/src/core/include/mp-units/customization_points.h +++ b/src/core/include/mp-units/customization_points.h @@ -132,11 +132,42 @@ struct quantity_values { } }; +template +struct convert_explicitly { + using value_type = T; + T value; + constexpr explicit(false) convert_explicitly(T v) noexcept(std::is_nothrow_constructible_v) : value(std::move(v)) + { + } +}; + +template +struct convert_implicitly { + using value_type = T; + T value; + constexpr explicit(false) convert_implicitly(T v) noexcept(std::is_nothrow_constructible_v) : value(std::move(v)) + { + } +}; + +namespace detail { + +template +concept ConversionSpec = is_specialization_of || is_specialization_of; + +template +concept ConversionSpecOf = ConversionSpec && std::same_as; + +} // namespace detail + /** * @brief Provides support for external quantity-like types * * The type trait should provide the @c reference object, a type alias @c rep, - * and a static member function @c value(T) that returns the raw value of the quantity. + * and static member functions @c to_numerical_value(T) that returns the raw value + * of the quantity and @c from_numerical_value(rep) that returns @c T from @c rep. + * Both return types should be encapsulated in either @c convert_explicitly or + * @c convert_implicitly to specify if the conversion is allowed to happen implicitly. * * Usage example can be found in @c units/chrono.h header file. * @@ -149,8 +180,11 @@ struct quantity_like_traits; * @brief Provides support for external quantity point-like types * * The type trait should provide nested @c reference and @c origin objects, - * a type alias @c rep, and a static member function @c quantity_from_origin(T) that will - * return the quantity being the offset of the point from the origin. + * a type alias @c rep, and static member functions @c to_quantity(T) that returns + * the quantity being the offset of the point from the origin and + * @c from_quantity(quantity) that returns @c T form this quantity. + * Both return types should be encapsulated in either @c convert_explicitly or + * @c convert_implicitly to specify if the conversion is allowed to happen implicitly. * * Usage example can be found in @c units/chrono.h header file. * diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 23a1f6c3..1970f016 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -133,8 +133,10 @@ public: template requires detail::QuantityConvertibleTo< quantity::reference, typename quantity_like_traits::rep>, quantity> - constexpr explicit quantity(const Q& q) : - quantity(make_quantity::reference>(quantity_like_traits::value(q))) + constexpr explicit( + is_specialization_of::to_numerical_value(std::declval())), convert_explicitly>) + quantity(const Q& q) : + quantity(make_quantity::reference>(quantity_like_traits::to_numerical_value(q).value)) { } @@ -189,6 +191,25 @@ public: return (*this).force_in(U{}).numerical_value_; } + // conversion operators + template + [[nodiscard]] explicit(is_specialization_of::from_numerical_value(numerical_value_)), + convert_explicitly>) constexpr + operator Q() const& noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && + std::is_nothrow_copy_constructible_v) + { + return quantity_like_traits::from_numerical_value(numerical_value_).value; + } + + template + [[nodiscard]] explicit(is_specialization_of::from_numerical_value(numerical_value_)), + convert_explicitly>) constexpr + operator Q() const&& noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && + std::is_nothrow_copy_constructible_v) + { + return quantity_like_traits::from_numerical_value(std::move(numerical_value_)).value; + } + // member unary operators [[nodiscard]] constexpr Quantity auto operator+() const requires requires(rep v) { @@ -365,7 +386,9 @@ private: // CTAD template -explicit quantity(Q) -> quantity::reference, typename quantity_like_traits::rep>; +explicit( + is_specialization_of::to_numerical_value(std::declval())), convert_explicitly>) + quantity(Q) -> quantity::reference, typename quantity_like_traits::rep>; // binary operators on quantities template diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 3e158770..5da5dd5e 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -128,8 +128,10 @@ public: std::convertible_to< quantity::reference, typename quantity_point_like_traits::rep>, quantity_type> - constexpr explicit quantity_point(const QP& qp) : - quantity_from_origin_(quantity_point_like_traits::quantity_from_origin(qp)) + constexpr explicit( + is_specialization_of::to_quantity(std::declval())), convert_explicitly>) + quantity_point(const QP& qp) : + quantity_from_origin_(quantity_point_like_traits::to_quantity(qp).value) { } @@ -182,6 +184,27 @@ public: return make_quantity_point(quantity_ref_from(PO).force_in(U{})); } + // conversion operators + template + [[nodiscard]] explicit( + is_specialization_of::from_quantity(quantity_from_origin_)), + convert_explicitly>) constexpr + operator QP() const& noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && + std::is_nothrow_copy_constructible_v) + { + return quantity_point_like_traits::from_quantity(quantity_from_origin_).value; + } + + template + [[nodiscard]] explicit( + is_specialization_of::from_quantity(quantity_from_origin_)), + convert_explicitly>) constexpr + operator QP() const&& noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && + std::is_nothrow_copy_constructible_v) + { + return quantity_point_like_traits::from_quantity(std::move(quantity_from_origin_)).value; + } + // member unary operators template friend constexpr decltype(auto) operator++(QP&& qp) @@ -249,9 +272,11 @@ private: // CTAD template -explicit quantity_point(QP) - -> quantity_point::reference, quantity_point_like_traits::point_origin, - typename quantity_point_like_traits::rep>; +explicit( + is_specialization_of::to_quantity(std::declval())), convert_explicitly>) + quantity_point(QP) + -> quantity_point::reference, quantity_point_like_traits::point_origin, + typename quantity_point_like_traits::rep>; template // TODO simplify when gcc catches up diff --git a/src/utility/include/mp-units/chrono.h b/src/utility/include/mp-units/chrono.h index f868d84b..d71372e3 100644 --- a/src/utility/include/mp-units/chrono.h +++ b/src/utility/include/mp-units/chrono.h @@ -64,7 +64,18 @@ template struct quantity_like_traits> { static constexpr auto reference = detail::time_unit_from_chrono_period(); using rep = Rep; - [[nodiscard]] static constexpr rep value(const std::chrono::duration& q) { return q.count(); } + + [[nodiscard]] static constexpr convert_implicitly to_numerical_value( + const std::chrono::duration& q) noexcept(std::is_nothrow_copy_constructible_v) + { + return q.count(); + } + + [[nodiscard]] static constexpr convert_implicitly> from_numerical_value( + const rep& v) noexcept(std::is_nothrow_copy_constructible_v) + { + return std::chrono::duration(v); + } }; template @@ -77,14 +88,22 @@ inline constexpr chrono_point_origin_ chrono_point_origin; template struct quantity_point_like_traits>> { + using T = std::chrono::time_point>; static constexpr auto reference = detail::time_unit_from_chrono_period(); static constexpr auto point_origin = chrono_point_origin; using rep = Rep; - [[nodiscard]] static constexpr quantity quantity_from_origin( - const std::chrono::time_point>& qp) + + [[nodiscard]] static constexpr convert_implicitly> to_quantity(const T& qp) noexcept( + std::is_nothrow_copy_constructible_v) { return quantity{qp.time_since_epoch()}; } + + [[nodiscard]] static constexpr convert_implicitly from_quantity(const quantity& q) noexcept( + std::is_nothrow_copy_constructible_v) + { + return T(q); + } }; template Q> @@ -92,7 +111,7 @@ template Q> { constexpr auto canonical = detail::get_canonical_unit(Q::unit); constexpr ratio r = as_ratio(canonical.mag); - return std::chrono::duration>{q.numerical_value_ref_in(Q::unit)}; + return std::chrono::duration>{q}; } template QP> diff --git a/test/unit_test/static/chrono_test.cpp b/test/unit_test/static/chrono_test.cpp index 75d87128..3b4059bb 100644 --- a/test/unit_test/static/chrono_test.cpp +++ b/test/unit_test/static/chrono_test.cpp @@ -52,40 +52,40 @@ static_assert(!QuantityPoint); // construction - same rep type static_assert( std::constructible_from, std::chrono::seconds>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, std::chrono::hours>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, std::chrono::hours>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(!std::constructible_from, std::chrono::seconds>); static_assert(!std::convertible_to>); static_assert( std::constructible_from, sys_seconds>); static_assert( !std::constructible_from, sys_seconds>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, sys_days>); static_assert(!std::constructible_from, sys_days>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, sys_days>); static_assert(!std::constructible_from, sys_days>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(!std::constructible_from, sys_seconds>); static_assert(!std::convertible_to>); // construction - different rep type (integral to a floating-point) static_assert(std::constructible_from, std::chrono::seconds>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, std::chrono::hours>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, std::chrono::seconds>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, sys_seconds>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, sys_days>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(std::constructible_from, sys_seconds>); -static_assert(!std::convertible_to>); +static_assert(std::convertible_to>); static_assert(quantity{1s} == 1 * s); static_assert(quantity{1s} == 1 * s); diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index 41acddeb..46e0b6d1 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -525,7 +525,7 @@ static_assert(!std::convertible_to, static_assert( std::constructible_from>, sys_seconds>); static_assert( - !std::convertible_to>>); + std::convertible_to>>); // incompatible origin static_assert( From 78bf9a9add012012d653e632ba77decb8d0ddd99 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 30 Sep 2023 04:34:19 +0200 Subject: [PATCH 04/10] Update src/core/include/mp-units/quantity.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Johel Ernesto Guerrero Peña --- src/core/include/mp-units/quantity.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 1970f016..f9fae4d7 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -204,8 +204,8 @@ public: template [[nodiscard]] explicit(is_specialization_of::from_numerical_value(numerical_value_)), convert_explicitly>) constexpr - operator Q() const&& noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && - std::is_nothrow_copy_constructible_v) + operator Q() && noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && + std::is_nothrow_move_constructible_v) { return quantity_like_traits::from_numerical_value(std::move(numerical_value_)).value; } From 099927468074a6fc13d9437f86c0211781c1d109 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 30 Sep 2023 04:34:46 +0200 Subject: [PATCH 05/10] Update src/core/include/mp-units/quantity_point.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Johel Ernesto Guerrero Peña --- src/core/include/mp-units/quantity_point.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 5da5dd5e..068a4a40 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -199,8 +199,8 @@ public: [[nodiscard]] explicit( is_specialization_of::from_quantity(quantity_from_origin_)), convert_explicitly>) constexpr - operator QP() const&& noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && - std::is_nothrow_copy_constructible_v) + operator QP() && noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && + std::is_nothrow_move_constructible_v) { return quantity_point_like_traits::from_quantity(std::move(quantity_from_origin_)).value; } From b12b9f87ae275a51876bb14702a22cb2e573e24d Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 30 Sep 2023 22:14:20 -0600 Subject: [PATCH 06/10] feat: `quantity` and `quantity_point` conversion operators now can also convert to const references --- src/core/include/mp-units/quantity.h | 10 ++++++---- src/core/include/mp-units/quantity_point.h | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index f9fae4d7..afc1ad2b 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -143,7 +143,7 @@ public: quantity& operator=(const quantity&) = default; quantity& operator=(quantity&&) = default; - // conversions + // unit conversions template U> requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr Quantity auto in(U) const @@ -192,7 +192,8 @@ public: } // conversion operators - template + template + requires QuantityLike> [[nodiscard]] explicit(is_specialization_of::from_numerical_value(numerical_value_)), convert_explicitly>) constexpr operator Q() const& noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && @@ -201,11 +202,12 @@ public: return quantity_like_traits::from_numerical_value(numerical_value_).value; } - template + template + requires QuantityLike> [[nodiscard]] explicit(is_specialization_of::from_numerical_value(numerical_value_)), convert_explicitly>) constexpr operator Q() && noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && - std::is_nothrow_move_constructible_v) + std::is_nothrow_move_constructible_v) { return quantity_like_traits::from_numerical_value(std::move(numerical_value_)).value; } diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 068a4a40..3095d0fb 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -170,6 +170,7 @@ public: return *this - PO2{}; } + // unit conversions template U> requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr QuantityPoint auto in(U) const @@ -185,7 +186,8 @@ public: } // conversion operators - template + template + requires QuantityPointLike> [[nodiscard]] explicit( is_specialization_of::from_quantity(quantity_from_origin_)), convert_explicitly>) constexpr @@ -195,12 +197,13 @@ public: return quantity_point_like_traits::from_quantity(quantity_from_origin_).value; } - template + template + requires QuantityPointLike> [[nodiscard]] explicit( is_specialization_of::from_quantity(quantity_from_origin_)), convert_explicitly>) constexpr operator QP() && noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && - std::is_nothrow_move_constructible_v) + std::is_nothrow_move_constructible_v) { return quantity_point_like_traits::from_quantity(std::move(quantity_from_origin_)).value; } From 2281be0f766da165af338a89b3179e74e2ba9961 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 2 Oct 2023 21:12:25 -0600 Subject: [PATCH 07/10] feat: `QuantityLike` and `QuantityPointLike` conversions improved --- src/core/include/mp-units/quantity.h | 30 +++++++++++-------- src/core/include/mp-units/quantity_point.h | 35 +++++++++++++++------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index afc1ad2b..96178dc9 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -133,9 +133,9 @@ public: template requires detail::QuantityConvertibleTo< quantity::reference, typename quantity_like_traits::rep>, quantity> - constexpr explicit( - is_specialization_of::to_numerical_value(std::declval())), convert_explicitly>) - quantity(const Q& q) : + constexpr explicit(is_specialization_of::to_numerical_value(std::declval())), + convert_explicitly> || + !std::convertible_to) quantity(const Q& q) : quantity(make_quantity::reference>(quantity_like_traits::to_numerical_value(q).value)) { } @@ -192,22 +192,26 @@ public: } // conversion operators - template - requires QuantityLike> + template> + requires detail::QuantityConvertibleTo< + quantity, quantity::reference, typename quantity_like_traits::rep>> [[nodiscard]] explicit(is_specialization_of::from_numerical_value(numerical_value_)), - convert_explicitly>) constexpr - operator Q() const& noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && - std::is_nothrow_copy_constructible_v) + convert_explicitly> || + !std::convertible_to) constexpr + operator Q_() const& noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && + std::is_nothrow_copy_constructible_v) { return quantity_like_traits::from_numerical_value(numerical_value_).value; } - template - requires QuantityLike> + template> + requires detail::QuantityConvertibleTo< + quantity, quantity::reference, typename quantity_like_traits::rep>> [[nodiscard]] explicit(is_specialization_of::from_numerical_value(numerical_value_)), - convert_explicitly>) constexpr - operator Q() && noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && - std::is_nothrow_move_constructible_v) + convert_explicitly> || + !std::convertible_to) constexpr + operator Q_() && noexcept(noexcept(quantity_like_traits::from_numerical_value(numerical_value_)) && + std::is_nothrow_move_constructible_v) { return quantity_like_traits::from_numerical_value(std::move(numerical_value_)).value; } diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 3095d0fb..22e37ac9 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -129,7 +129,10 @@ public: quantity::reference, typename quantity_point_like_traits::rep>, quantity_type> constexpr explicit( - is_specialization_of::to_quantity(std::declval())), convert_explicitly>) + is_specialization_of::to_quantity(std::declval())), + convert_explicitly> || + !std::convertible_to< + quantity::reference, typename quantity_point_like_traits::rep>, quantity_type>) quantity_point(const QP& qp) : quantity_from_origin_(quantity_point_like_traits::to_quantity(qp).value) { @@ -186,24 +189,34 @@ public: } // conversion operators - template - requires QuantityPointLike> + template> + requires std::same_as, + std::remove_const_t::point_origin)>> && + std::convertible_to::reference, + typename quantity_point_like_traits::rep>> [[nodiscard]] explicit( is_specialization_of::from_quantity(quantity_from_origin_)), - convert_explicitly>) constexpr - operator QP() const& noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && - std::is_nothrow_copy_constructible_v) + convert_explicitly> || + !std::convertible_to::reference, + typename quantity_point_like_traits::rep>>) constexpr + operator QP_() const& noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && + std::is_nothrow_copy_constructible_v) { return quantity_point_like_traits::from_quantity(quantity_from_origin_).value; } - template - requires QuantityPointLike> + template> + requires std::same_as, + std::remove_const_t::point_origin)>> && + std::convertible_to::reference, + typename quantity_point_like_traits::rep>> [[nodiscard]] explicit( is_specialization_of::from_quantity(quantity_from_origin_)), - convert_explicitly>) constexpr - operator QP() && noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && - std::is_nothrow_move_constructible_v) + convert_explicitly> || + !std::convertible_to::reference, + typename quantity_point_like_traits::rep>>) constexpr + operator QP_() && noexcept(noexcept(quantity_point_like_traits::from_quantity(quantity_from_origin_)) && + std::is_nothrow_move_constructible_v) { return quantity_point_like_traits::from_quantity(std::move(quantity_from_origin_)).value; } From 00a2bce0e820560cb178f6c7ccab7399fdbadc2c Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 3 Oct 2023 11:00:33 -0600 Subject: [PATCH 08/10] fix(example): `latitude` and `longitude` fixed to include `0` for `N` and `E` respectively --- example/include/geographic.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/example/include/geographic.h b/example/include/geographic.h index c422fa76..b704dd24 100644 --- a/example/include/geographic.h +++ b/example/include/geographic.h @@ -79,7 +79,7 @@ using longitude = mp_units::quantity_point std::basic_ostream& operator<<(std::basic_ostream& os, const latitude& lat) { - if (is_gt_zero(lat)) + if (is_gteq_zero(lat)) return os << lat.quantity_from_origin() << " N"; else return os << -lat.quantity_from_origin() << " S"; @@ -88,7 +88,7 @@ std::basic_ostream& operator<<(std::basic_ostream& template std::basic_ostream& operator<<(std::basic_ostream& os, const longitude& lon) { - if (is_gt_zero(lon)) + if (is_gteq_zero(lon)) return os << lon.quantity_from_origin() << " E"; else return os << -lon.quantity_from_origin() << " W"; @@ -138,8 +138,8 @@ struct MP_UNITS_STD_FMT::formatter> : auto format(geographic::latitude lat, FormatContext& ctx) { formatter::quantity_type>::format( - is_gt_zero(lat) ? lat.quantity_from(geographic::equator) : -lat.quantity_from(geographic::equator), ctx); - MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lat) ? " N" : "S"); + is_gteq_zero(lat) ? lat.quantity_from(geographic::equator) : -lat.quantity_from(geographic::equator), ctx); + MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gteq_zero(lat) ? " N" : "S"); return ctx.out(); } }; @@ -151,9 +151,10 @@ struct MP_UNITS_STD_FMT::formatter> : auto format(geographic::longitude lon, FormatContext& ctx) { formatter::quantity_type>::format( - is_gt_zero(lon) ? lon.quantity_from(geographic::prime_meridian) : -lon.quantity_from(geographic::prime_meridian), + is_gteq_zero(lon) ? lon.quantity_from(geographic::prime_meridian) + : -lon.quantity_from(geographic::prime_meridian), ctx); - MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lon) ? " E" : " W"); + MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gteq_zero(lon) ? " E" : " W"); return ctx.out(); } }; From 25f986d32cd3f7863a67bca547a2639457d0c343 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 4 Oct 2023 10:00:17 -0600 Subject: [PATCH 09/10] fix: MSVC-related fixes and workarounds --- example/measurement.cpp | 8 +- src/core-fmt/include/mp-units/bits/fmt.h | 9 ++- .../include/mp-units/bits/get_common_base.h | 4 +- src/core/include/mp-units/quantity_point.h | 3 +- src/core/include/mp-units/quantity_spec.h | 74 ++++++++++--------- src/core/include/mp-units/reference.h | 17 +++++ src/core/include/mp-units/system_reference.h | 5 ++ src/core/include/mp-units/unit.h | 10 +-- 8 files changed, 78 insertions(+), 52 deletions(-) diff --git a/example/measurement.cpp b/example/measurement.cpp index b6741627..c20d8224 100644 --- a/example/measurement.cpp +++ b/example/measurement.cpp @@ -134,11 +134,11 @@ void example() using namespace mp_units; using namespace mp_units::si::unit_symbols; - const auto a = isq::acceleration(measurement{9.8, 0.1} * (m / s2)); - const auto t = measurement{1.2, 0.1} * s; + const auto acceleration = isq::acceleration(measurement{9.8, 0.1} * (m / s2)); + const auto time = measurement{1.2, 0.1} * s; - const QuantityOf auto v = a * t; - std::cout << a << " * " << t << " = " << v << " = " << v.in(km / h) << '\n'; + const QuantityOf auto velocity = acceleration * time; + std::cout << acceleration << " * " << time << " = " << velocity << " = " << velocity.in(km / h) << '\n'; const auto length = measurement{123., 1.} * m; std::cout << "10 * " << length << " = " << 10 * length << '\n'; diff --git a/src/core-fmt/include/mp-units/bits/fmt.h b/src/core-fmt/include/mp-units/bits/fmt.h index 95ef4549..973f01ad 100644 --- a/src/core-fmt/include/mp-units/bits/fmt.h +++ b/src/core-fmt/include/mp-units/bits/fmt.h @@ -103,9 +103,9 @@ struct width_checker { if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative width")); } return static_cast(value); - } else { - MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer")); } + MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer")); + return 0; // should never happen } }; @@ -118,9 +118,9 @@ struct precision_checker { if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative precision")); } return static_cast(value); - } else { - MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("precision is not integer")); } + MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("precision is not integer")); + return 0; // should never happen } }; @@ -230,6 +230,7 @@ template S, typename IDHandler> return begin; } MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("invalid format string")); + return begin; // should never happen } template S, typename IDHandler> diff --git a/src/core/include/mp-units/bits/get_common_base.h b/src/core/include/mp-units/bits/get_common_base.h index 0c232dc1..97ad5fbd 100644 --- a/src/core/include/mp-units/bits/get_common_base.h +++ b/src/core/include/mp-units/bits/get_common_base.h @@ -58,8 +58,8 @@ template template [[nodiscard]] consteval auto have_common_base(A a, B b) { - constexpr int a_length = hierarchy_path_length(A{}); - constexpr int b_length = hierarchy_path_length(B{}); + constexpr std::size_t a_length = hierarchy_path_length(A{}); + constexpr std::size_t b_length = hierarchy_path_length(B{}); if constexpr (a_length > b_length) return have_common_base_in_hierarchy_of_equal_length(hierarchy_path_advance(a), b); else diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 22e37ac9..6cf8308b 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -142,7 +142,8 @@ public: quantity_point& operator=(quantity_point&&) = default; template NewPO> - [[nodiscard]] constexpr QuantityPointOf auto point_for(NewPO new_origin) const + [[nodiscard]] constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(QuantityPointOf) auto point_for( + NewPO new_origin) const { if constexpr (is_same_v>) return *this; diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index b94e476c..22cc47bb 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -41,12 +41,12 @@ namespace detail { template requires(!AssociatedUnit) || UnitOf -[[nodiscard]] consteval Reference auto make_reference(QS qs, U u) +[[nodiscard]] consteval Reference auto make_reference(QS, U u) { if constexpr (detail::QuantityKindSpec) return u; else - return reference{}; + return reference{}; } // TODO revise the note in the below comment @@ -494,9 +494,10 @@ template // Operators -[[nodiscard]] consteval QuantitySpec auto operator*(QuantitySpec auto lhs, QuantitySpec auto rhs) +template +[[nodiscard]] consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs) { - return clone_kind_of( + return clone_kind_of( detail::expr_multiply( remove_kind(lhs), remove_kind(rhs))); } @@ -504,15 +505,16 @@ template template [[nodiscard]] consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs) { - return clone_kind_of( + return clone_kind_of( detail::expr_divide( remove_kind(lhs), remove_kind(rhs))); } -[[nodiscard]] consteval QuantitySpec auto operator/(int value, QuantitySpec auto q) +template +[[nodiscard]] consteval QuantitySpec auto operator/(int value, QS qs) { gsl_Expects(value == 1); - return clone_kind_of(detail::expr_invert(q)); + return clone_kind_of(detail::expr_invert(qs)); } [[nodiscard]] consteval QuantitySpec auto operator/(QuantitySpec auto, int) = delete; @@ -554,7 +556,7 @@ template // `2 * one * (2 * one)` should compare to `4 * one` // `2 * rad * (2 * rad)` should compare to `4 * rad^2` // all are dimensionless quantities :-( - if constexpr (Num == 0 || q == dimensionless) + if constexpr (Num == 0 || Q{} == dimensionless) return dimensionless; else if constexpr (ratio{Num, Den} == 1) return q; @@ -779,7 +781,7 @@ template template [[nodiscard]] consteval auto explode(Q q) { - constexpr auto c = get_complexity(q); + constexpr auto c = get_complexity(Q{}); if constexpr (c > Complexity) return explode(q, type_list_sort{}, type_list_sort{}); @@ -790,9 +792,9 @@ template template [[nodiscard]] consteval auto explode(Q q) { - constexpr auto c = get_complexity(q); + constexpr auto c = get_complexity(Q{}); if constexpr (c > Complexity && requires { Q::_equation_; }) { - constexpr auto res = explode_to_equation(q); + constexpr auto res = explode_to_equation(Q{}); return explode(res.equation).common_convertibility_with(res); } else return explode_result{q}; @@ -887,8 +889,8 @@ extract_results(bool, From = {}, To = {}, prepend_rest = {}, Elem = {}) -> extra template [[nodiscard]] consteval auto extract_convertible_quantities(From from, To to) { - constexpr auto qfrom = map_power(from); - constexpr auto qto = map_power(to); + constexpr auto qfrom = map_power(From{}); + constexpr auto qto = map_power(To{}); if constexpr (qfrom.dimension == qto.dimension) { if constexpr (is_specialization_of_power && is_specialization_of_power) { constexpr auto cr = common_ratio(From::exponent, To::exponent); @@ -905,8 +907,8 @@ template else return std::tuple{Q{}, ratio{1}}; }; - constexpr auto from_norm = normalize(from); - constexpr auto to_norm = normalize(to); + constexpr auto from_norm = normalize(From{}); + constexpr auto to_norm = normalize(To{}); constexpr auto from_factor = std::get<0>(from_norm); constexpr auto from_exp = std::get<1>(from_norm); constexpr auto to_factor = std::get<0>(to_norm); @@ -1335,11 +1337,11 @@ template if constexpr (From::dimension != To::dimension) return no; - else if constexpr (from == to) + else if constexpr (From{} == To{}) return yes; else if constexpr (QuantityKindSpec || QuantityKindSpec) { - constexpr auto from_kind = get_kind(from); - constexpr auto to_kind = get_kind(to); + constexpr auto from_kind = get_kind(From{}); + constexpr auto to_kind = get_kind(To{}); constexpr auto exploded_kind_result = [](specs_convertible_result res) { using enum specs_convertible_result; return res == no ? no : yes; @@ -1354,21 +1356,21 @@ template else return exploded_kind_result( convertible_impl(from_kind, get_kind(explode(to_kind).quantity))); - } else if constexpr (NestedQuantityKindSpecOf && get_kind(to) == to) + } else if constexpr (NestedQuantityKindSpecOf && get_kind(To{}) == To{}) return yes; else if constexpr (NamedQuantitySpec && NamedQuantitySpec) { - if constexpr (have_common_base(from, to)) { + if constexpr (have_common_base(From{}, To{})) { if (std::derived_from) return yes; else return std::derived_from ? explicit_conversion : (get_kind(from) == get_kind(to) ? cast : no); - } else if constexpr (get_kind(from) != get_kind(to)) + } else if constexpr (get_kind(From{}) != get_kind(To{})) return no; - else if constexpr (get_complexity(from) != get_complexity(to)) { - if constexpr (get_complexity(from) > get_complexity(to)) + else if constexpr (get_complexity(From{}) != get_complexity(To{})) { + if constexpr (get_complexity(From{}) > get_complexity(To{})) return convertible_impl(explode(from).quantity, to); else { - constexpr auto res = explode(to); + auto res = explode(to); return min(res.result, convertible_impl(from, res.quantity)); } } @@ -1379,7 +1381,7 @@ template if constexpr (NamedQuantitySpec>) return convertible_impl(res.quantity, to); else if constexpr (requires { to._equation_; }) { - constexpr auto eq = explode_to_equation(to); + auto eq = explode_to_equation(to); return min(eq.result, convertible_impl(res.quantity, eq.equation)); } else return are_ingredients_convertible(from, to); @@ -1449,16 +1451,16 @@ template template [[nodiscard]] consteval QuantitySpec auto get_kind(Q q) { - auto defined_as_kind = [](auto qq) { + auto defined_as_kind = [](QQ qq) { if constexpr (requires { detail::defined_as_kind(qq); }) - return detail::defined_as_kind(qq); + return detail::defined_as_kind(QQ{}); else return false; }; if constexpr (detail::QuantityKindSpec) { return remove_kind(q); - } else if constexpr (defined_as_kind(q)) { + } else if constexpr (defined_as_kind(Q{})) { return q; } else if constexpr (requires { Q::_parent_; }) { return get_kind(Q::_parent_); @@ -1481,25 +1483,25 @@ template using QQ2 = std::remove_const_t; if constexpr (is_same_v) return q1; - else if constexpr (detail::NestedQuantityKindSpecOf) + else if constexpr (detail::NestedQuantityKindSpecOf) return remove_kind(q1); - else if constexpr (detail::NestedQuantityKindSpecOf) + else if constexpr (detail::NestedQuantityKindSpecOf) return remove_kind(q2); else if constexpr ((detail::QuantityKindSpec && !detail::QuantityKindSpec) || (detail::IntermediateDerivedQuantitySpec && detail::NamedQuantitySpec && - implicitly_convertible(q1, q2))) + implicitly_convertible(Q1{}, Q2{}))) return q2; else if constexpr ((!detail::QuantityKindSpec && detail::QuantityKindSpec) || (detail::NamedQuantitySpec && detail::IntermediateDerivedQuantitySpec && - implicitly_convertible(q2, q1))) + implicitly_convertible(Q2{}, Q1{}))) return q1; - else if constexpr (detail::have_common_base(q1, q2)) + else if constexpr (detail::have_common_base(Q1{}, Q2{})) return detail::get_common_base(q1, q2); - else if constexpr (implicitly_convertible(q1, q2)) + else if constexpr (implicitly_convertible(Q1{}, Q2{})) return q2; - else if constexpr (implicitly_convertible(q2, q1)) + else if constexpr (implicitly_convertible(Q2{}, Q1{})) return q1; - else if constexpr (implicitly_convertible(get_kind(q1), get_kind(q2))) + else if constexpr (implicitly_convertible(get_kind(Q1{}), get_kind(Q2{}))) return get_kind(q2); else return get_kind(q1); diff --git a/src/core/include/mp-units/reference.h b/src/core/include/mp-units/reference.h index 032c4192..1633336b 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 @@ -73,13 +74,21 @@ struct reference { } template +#if MP_UNITS_COMP_MSVC + [[nodiscard]] friend consteval decltype(reference{}) operator*(reference, U2) +#else [[nodiscard]] friend consteval reference operator*(reference, U2) +#endif { return {}; } template +#if MP_UNITS_COMP_MSVC + [[nodiscard]] friend consteval decltype(reference{}) operator*(U1, reference) +#else [[nodiscard]] friend consteval reference operator*(U1, reference) +#endif { return {}; } @@ -91,13 +100,21 @@ struct reference { } template +#if MP_UNITS_COMP_MSVC + [[nodiscard]] friend consteval decltype(reference{}) operator/(reference, U2) +#else [[nodiscard]] friend consteval reference operator/(reference, U2) +#endif { return {}; } template +#if MP_UNITS_COMP_MSVC + [[nodiscard]] friend consteval decltype(reference{}) operator/(U1, reference) +#else [[nodiscard]] friend consteval reference operator/(U1, reference) +#endif { return {}; } diff --git a/src/core/include/mp-units/system_reference.h b/src/core/include/mp-units/system_reference.h index 32568569..59f4769c 100644 --- a/src/core/include/mp-units/system_reference.h +++ b/src/core/include/mp-units/system_reference.h @@ -22,6 +22,7 @@ #pragma once +#include #include #include #include @@ -63,7 +64,11 @@ struct system_reference { template requires(convertible(coherent_unit, U{})) +#if MP_UNITS_COMP_MSVC + [[nodiscard]] constexpr decltype(reference{}) operator[](U) const +#else [[nodiscard]] constexpr reference operator[](U) const +#endif { return {}; } diff --git a/src/core/include/mp-units/unit.h b/src/core/include/mp-units/unit.h index c4343c45..ca3068cf 100644 --- a/src/core/include/mp-units/unit.h +++ b/src/core/include/mp-units/unit.h @@ -354,9 +354,9 @@ template template [[nodiscard]] consteval auto get_canonical_unit_impl(const type_list&) { - auto mag = (mp_units::mag<1> * ... * get_canonical_unit_impl(Us{}, Us{}).mag); + auto m = (mp_units::mag<1> * ... * get_canonical_unit_impl(Us{}, Us{}).mag); auto u = (one * ... * get_canonical_unit_impl(Us{}, Us{}).reference_unit); - return canonical_unit{mag, u}; + return canonical_unit{m, u}; } template @@ -402,12 +402,12 @@ using type_list_of_unit_less = expr_less; * Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned. */ template -[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M mag, const U u) +[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M, const U u) { - if constexpr (mag == mp_units::mag<1>) + if constexpr (std::is_same_v)>>) return u; else - return scaled_unit{}; + return scaled_unit{}; } [[nodiscard]] consteval Unit auto operator*(Unit auto, Magnitude auto) = delete; From fa5419b7920ef0bf90f564b58bcb4a350a55581e Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 4 Oct 2023 10:14:57 -0600 Subject: [PATCH 10/10] fix: unused parametrs identifiers removed --- src/core/include/mp-units/quantity_spec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index 22cc47bb..ef224b9e 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -887,7 +887,7 @@ extract_results(bool, From = {}, To = {}, prepend_rest = {}, Elem = {}) -> extra #endif template -[[nodiscard]] consteval auto extract_convertible_quantities(From from, To to) +[[nodiscard]] consteval auto extract_convertible_quantities(From, To) { constexpr auto qfrom = map_power(From{}); constexpr auto qto = map_power(To{});