From 9cd0cb41050f301e6baf26611ba5fb4e990e961f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 10 Sep 2020 13:01:38 +0200 Subject: [PATCH] feat: two argument explicit cast support added --- docs/framework/conversions_and_casting.rst | 11 +++- example/hello_units.cpp | 4 ++ example/measurement.cpp | 4 ++ src/include/units/quantity_cast.h | 56 +++++++++++++++++-- test/unit_test/runtime/fmt_test.cpp | 2 +- test/unit_test/static/quantity_point_test.cpp | 1 + test/unit_test/static/quantity_test.cpp | 5 +- 7 files changed, 72 insertions(+), 11 deletions(-) diff --git a/docs/framework/conversions_and_casting.rst b/docs/framework/conversions_and_casting.rst index 5ea37905..52fe490f 100644 --- a/docs/framework/conversions_and_casting.rst +++ b/docs/framework/conversions_and_casting.rst @@ -78,16 +78,21 @@ Quantity Cast Overloads :linenos: std::cout << "Distance: " << quantity_cast>(d) << '\n'; + std::cout << "Distance: " << quantity_cast(d) << '\n'; std::cout << "Distance: " << quantity_cast(d) << '\n'; std::cout << "Distance: " << quantity_cast(d) << '\n'; + std::cout << "Distance: " << quantity_cast(d) << '\n'; `quantity_cast` in line #1 takes a specific target `quantity` type to which an explicit cast should be performed. This option will change multiple quantity properties at once -(unit, representation, etc). However, it is also possible to force only one property at +(unit, representation, etc). However, it is also possible to force only some properties at once and leave the rest intact: -- line #2 forces only a specific destination unit type, -- line #3 sets only a representation type to the type provided by the user. +- line #2 forces only a specific destination dimension type, +- line #3 forces only a specific destination unit type, +- line #4 sets only a representation type to the type provided by the user, +- line #5 forces both a specific dimension and a unit while preserving the original + representation type. `quantity_point_cast` takes anything that works for `quantity_point` or a specific target `quantity_point`:: diff --git a/example/hello_units.cpp b/example/hello_units.cpp index 73e31fb4..cad84cf8 100644 --- a/example/hello_units.cpp +++ b/example/hello_units.cpp @@ -37,7 +37,11 @@ int main() using namespace units::physical::si::literals; Speed auto v1 = avg_speed(220_q_km, 2_q_h); Speed auto v2 = avg_speed(si::length(140), si::time(2)); +#if DOWNCAST_MODE == 0 + Speed auto v3 = quantity_cast(v2); +#else Speed auto v3 = quantity_cast(v2); +#endif Speed auto v4 = quantity_cast(v3); std::cout << v1 << '\n'; // 110 km/h diff --git a/example/measurement.cpp b/example/measurement.cpp index ce1d2b73..88fb1a3c 100644 --- a/example/measurement.cpp +++ b/example/measurement.cpp @@ -131,7 +131,11 @@ void example() const auto t = si::time>(measurement(1.2, 0.1)); const Speed auto v1 = a * t; +#if DOWNCAST_MODE == 0 + std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast(v1) << '\n'; +#else std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast(v1) << '\n'; +#endif si::length> length(measurement(123., 1.)); std::cout << "10 * " << length << " = " << 10 * length << '\n'; diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h index 6f05649b..e31b179a 100644 --- a/src/include/units/quantity_cast.h +++ b/src/include/units/quantity_cast.h @@ -301,7 +301,7 @@ constexpr ratio cast_ratio(const Q1& from, const Q2& to) } // namespace detail /** - * @brief Explcit cast of a quantity + * @brief Explicit cast of a quantity * * Implicit conversions between quantities of different types are allowed only for "safe" * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. @@ -325,7 +325,7 @@ template } /** - * @brief Explcit cast of a quantity + * @brief Explicit cast of a quantity * * Implicit conversions between quantities of different types are allowed only for "safe" * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. @@ -344,7 +344,7 @@ template } /** - * @brief Explcit cast of a quantity + * @brief Explicit cast of a quantity * * Implicit conversions between quantities of different types are allowed only for "safe" * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. @@ -363,7 +363,30 @@ template } /** - * @brief Explcit cast of a quantity + * @brief Explicit cast of a quantity + * + * Implicit conversions between quantities of different types are allowed only for "safe" + * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. + * + * This cast gets both the target dimension and unit to cast to. For example: + * + * auto q1 = units::quantity_cast(v1); + * + * @note This cast is especially useful when working with quantities of unknown dimensions + * (@c unknown_dimension). + * + * @tparam ToD a dimension type to use for a target quantity + * @tparam ToU a unit type to use for a target quantity + */ +template + requires equivalent && UnitOf +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) +{ + return quantity_cast>(q); +} + +/** + * @brief Explicit cast of a quantity * * Implicit conversions between quantities of different types are allowed only for "safe" * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. @@ -381,7 +404,7 @@ template } /** - * @brief Explcit cast of a quantity point + * @brief Explicit cast of a quantity point * * Implicit conversions between quantity points of different types are allowed only for "safe" * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used. @@ -407,6 +430,29 @@ template return quantity_point(quantity_cast(qp.relative())); } +/** + * @brief Explicit cast of a quantity point + * + * Implicit conversions between quantity points of different types are allowed only for "safe" + * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used. + * + * This cast gets both the target dimension and unit to cast to. For example: + * + * auto q1 = units::quantity_point_cast(v1); + * + * @note This cast is especially useful when working with quantity points of unknown dimensions + * (@c unknown_dimension). + * + * @tparam ToD a dimension type to use for a target quantity + * @tparam ToU a unit type to use for a target quantity + */ +template + requires equivalent && UnitOf +[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point& q) +{ + return quantity_point_cast>(q); +} + } // namespace units #ifdef _MSC_VER diff --git a/test/unit_test/runtime/fmt_test.cpp b/test/unit_test/runtime/fmt_test.cpp index 16aa3202..9cf6576e 100644 --- a/test/unit_test/runtime/fmt_test.cpp +++ b/test/unit_test/runtime/fmt_test.cpp @@ -468,7 +468,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("percents") { #if DOWNCAST_MODE == 0 - const auto q = quantity_cast>(15._q_m / 100._q_m); + const auto q = quantity_cast(15._q_m / 100._q_m); #else const auto q = quantity_cast(15._q_m / 100._q_m); #endif diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index 21670ada..edd56f7f 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -223,6 +223,7 @@ static_assert(quantity_point_cast>(quantity_point(1.23_q_m)). static_assert(quantity_point_cast(quantity_point(2_q_km)).relative().count() == 2000); static_assert(quantity_point_cast(quantity_point(2000_q_m)).relative().count() == 2); static_assert(quantity_point_cast(quantity_point(1.23_q_m)).relative().count() == 1); +static_assert(quantity_point_cast(quantity_point(2000.0_q_m / 3600.0_q_s)).relative().count() == 2); // time diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index f8865ecf..df3623db 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -201,7 +201,7 @@ constexpr dimensionless q2 = q1; static_assert(q2.count() == 2000); #if DOWNCAST_MODE == 0 -static_assert(quantity_cast>(q1).count() == 2000); +static_assert(quantity_cast(q1).count() == 2000); #else static_assert(quantity_cast(q1).count() == 2000); #endif @@ -282,6 +282,7 @@ static_assert(quantity_cast>(1.23_q_m).count() == 1); static_assert(quantity_cast(2_q_km).count() == 2000); static_assert(quantity_cast(2000_q_m).count() == 2); static_assert(quantity_cast(1.23_q_m).count() == 1); +static_assert(quantity_cast(2000.0_q_m / 3600.0_q_s).count() == 2); // dimensionless @@ -313,7 +314,7 @@ static_assert(invalid_dimensionless_operations); static_assert(compare>); #if DOWNCAST_MODE == 0 -static_assert(quantity_cast>(50._q_m / 100._q_m).count() == 50); +static_assert(quantity_cast(50._q_m / 100._q_m).count() == 50); #else static_assert(quantity_cast(50._q_m / 100._q_m).count() == 50); #endif