diff --git a/CHANGELOG.md b/CHANGELOG.md index efe2a403..0fa00699 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - feat: `fma`, `isfinite`, `isinf`, and `isnan` math function added by [@NAThompson](https://github.com/NAThompson) - feat: `quantity_point` support added for `quantity_cast` and `value_cast` - feat: `value_cast` added +- feat: `value_cast(q)`, `value_cast(qp)` and `value_cast(qp)` added by [@burnpanck](https://github.com/burnpanck) - feat: `interconvertible(QuantitySpec, QuantitySpec)` added - feat: `qp.quantity_from_zero()` added - feat: `underlying_type` type trait added diff --git a/docs/users_guide/framework_basics/value_conversions.md b/docs/users_guide/framework_basics/value_conversions.md index bed6e928..a296da3f 100644 --- a/docs/users_guide/framework_basics/value_conversions.md +++ b/docs/users_guide/framework_basics/value_conversions.md @@ -147,3 +147,17 @@ using namespace unit_symbols; Price price{12.95 * USD}; Scaled spx = value_cast(price); ``` + +As a shortcut, instead of providing a unit and a representation type to `value_cast`, you may also provide a +`Quantity` type directly, from which unit and representation type are taken. However, `value_cast`, +still only allows for changes in unit and representation type, but not changing the type of the quantity. +For that, you will have to use a `quantity_cast` instead. + +Overloads are also provided for instances of `quantity_point`. Furthermore, in that case, there is +an overload `value_cast(qp)`, which is roughly equivalent to +`value_cast(qp).point_for(ToQP::point_origin)`. +In contrast to a separate `value_cast` followed by `point_for` (or vice-versa), the combined +`value_cast` tries to choose the order of the individual conversion steps in such a way, +to avoid both overflow and unnecessary loss of precision. Overflow is a risk because the change of origin point +may require an addition of a potentially large offset (the difference between the origin points), +which may well be outside the range of one or both quantity types. diff --git a/src/core/include/mp-units/framework/value_cast.h b/src/core/include/mp-units/framework/value_cast.h index 4a2d55ce..a1ca3418 100644 --- a/src/core/include/mp-units/framework/value_cast.h +++ b/src/core/include/mp-units/framework/value_cast.h @@ -232,7 +232,8 @@ template [[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp) { using qp_type = std::remove_reference_t; - if constexpr (is_same_v, std::remove_const_t>) { + if constexpr (is_same_v, + std::remove_const_t>) { return quantity_point{ value_cast(std::forward(qp).quantity_from(qp_type::point_origin)), qp_type::point_origin}; diff --git a/test/static/quantity_point_test.cpp b/test/static/quantity_point_test.cpp index 68518bf4..7c0e001c 100644 --- a/test/static/quantity_point_test.cpp +++ b/test/static/quantity_point_test.cpp @@ -1706,15 +1706,15 @@ static_assert(value_cast_is_forbidden, quantity_point, quantity_point>(), "value_cast shall not cast between different quantity types"); -static_assert(value_cast>(quantity_point{2 * isq::height[km], ground_level}) - .quantity_from_origin_is_an_implementation_detail_ - .numerical_value_in(m) == 2042); -static_assert(value_cast>(quantity_point{std::int8_t{100} * isq::height[mm], ground_level}) - .quantity_from_origin_is_an_implementation_detail_ - .numerical_value_in(cm) == 4210); -static_assert(value_cast>(quantity_point{4210 * isq::height[cm], mean_sea_level}) - .quantity_from_origin_is_an_implementation_detail_ - .numerical_value_in(mm) == 100); +static_assert(value_cast>(quantity_point{2 * isq::height[km], + ground_level}) + .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(m) == 2042); +static_assert(value_cast>( + quantity_point{std::int8_t{100} * isq::height[mm], ground_level}) + .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(cm) == 4210); +static_assert(value_cast>( + quantity_point{4210 * isq::height[cm], mean_sea_level}) + .quantity_from_origin_is_an_implementation_detail_.numerical_value_in(mm) == 100); } // namespace