feat: two argument explicit cast support added

This commit is contained in:
Mateusz Pusz
2020-09-10 13:01:38 +02:00
parent 44e8d39102
commit 9cd0cb4105
7 changed files with 72 additions and 11 deletions

View File

@ -78,16 +78,21 @@ Quantity Cast Overloads
:linenos:
std::cout << "Distance: " << quantity_cast<si::length<si::metre, int>>(d) << '\n';
std::cout << "Distance: " << quantity_cast<si::dim_length>(d) << '\n';
std::cout << "Distance: " << quantity_cast<si::metre>(d) << '\n';
std::cout << "Distance: " << quantity_cast<int>(d) << '\n';
std::cout << "Distance: " << quantity_cast<si::dim_length, si::metre>(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`::

View File

@ -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<international::mile>(140), si::time<si::hour>(2));
#if DOWNCAST_MODE == 0
Speed auto v3 = quantity_cast<si::dim_speed, si::metre_per_second>(v2);
#else
Speed auto v3 = quantity_cast<si::metre_per_second>(v2);
#endif
Speed auto v4 = quantity_cast<int>(v3);
std::cout << v1 << '\n'; // 110 km/h

View File

@ -131,7 +131,11 @@ void example()
const auto t = si::time<si::second, measurement<double>>(measurement(1.2, 0.1));
const Speed auto v1 = a * t;
#if DOWNCAST_MODE == 0
std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast<si::dim_speed, si::kilometre_per_hour>(v1) << '\n';
#else
std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast<si::kilometre_per_hour>(v1) << '\n';
#endif
si::length<si::metre, measurement<double>> length(measurement(123., 1.));
std::cout << "10 * " << length << " = " << 10 * length << '\n';

View File

@ -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<Quantity To, typename D, typename U, typename Rep>
}
/**
* @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<Dimension ToD, typename D, typename U, typename Rep>
}
/**
* @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<Unit ToU, typename D, typename U, typename Rep>
}
/**
* @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<units::physical::si::dim_speed, units::physical::si::kilometre_per_hour>(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<Dimension ToD, Unit ToU, typename D, typename U, typename Rep>
requires equivalent<ToD, D> && UnitOf<ToU, ToD>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
{
return quantity_cast<quantity<ToD, ToU, Rep>>(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<ScalableNumber ToRep, typename D, typename U, typename Rep>
}
/**
* @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<typename CastSpec, typename D, typename U, typename Rep>
return quantity_point(quantity_cast<CastSpec>(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<units::physical::si::dim_speed, units::physical::si::kilometre_per_hour>(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<Dimension ToD, Unit ToU, typename D, typename U, typename Rep>
requires equivalent<ToD, D> && UnitOf<ToU, ToD>
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<D, U, Rep>& q)
{
return quantity_point_cast<quantity_point<ToD, ToU, Rep>>(q);
}
} // namespace units
#ifdef _MSC_VER

View File

@ -468,7 +468,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
SECTION("percents")
{
#if DOWNCAST_MODE == 0
const auto q = quantity_cast<dimensionless<percent>>(15._q_m / 100._q_m);
const auto q = quantity_cast<dim_one, percent>(15._q_m / 100._q_m);
#else
const auto q = quantity_cast<percent>(15._q_m / 100._q_m);
#endif

View File

@ -223,6 +223,7 @@ static_assert(quantity_point_cast<length<metre, int>>(quantity_point(1.23_q_m)).
static_assert(quantity_point_cast<metre>(quantity_point(2_q_km)).relative().count() == 2000);
static_assert(quantity_point_cast<kilometre>(quantity_point(2000_q_m)).relative().count() == 2);
static_assert(quantity_point_cast<int>(quantity_point(1.23_q_m)).relative().count() == 1);
static_assert(quantity_point_cast<dim_speed, kilometre_per_hour>(quantity_point(2000.0_q_m / 3600.0_q_s)).relative().count() == 2);
// time

View File

@ -201,7 +201,7 @@ constexpr dimensionless<one> q2 = q1;
static_assert(q2.count() == 2000);
#if DOWNCAST_MODE == 0
static_assert(quantity_cast<dimensionless<one>>(q1).count() == 2000);
static_assert(quantity_cast<dim_one, one>(q1).count() == 2000);
#else
static_assert(quantity_cast<one>(q1).count() == 2000);
#endif
@ -282,6 +282,7 @@ static_assert(quantity_cast<length<metre, int>>(1.23_q_m).count() == 1);
static_assert(quantity_cast<metre>(2_q_km).count() == 2000);
static_assert(quantity_cast<kilometre>(2000_q_m).count() == 2);
static_assert(quantity_cast<int>(1.23_q_m).count() == 1);
static_assert(quantity_cast<dim_speed, kilometre_per_hour>(2000.0_q_m / 3600.0_q_s).count() == 2);
// dimensionless
@ -313,7 +314,7 @@ static_assert(invalid_dimensionless_operations<int>);
static_assert(compare<decltype(10_q_km / 5_q_km), quantity<dim_one, one, std::int64_t>>);
#if DOWNCAST_MODE == 0
static_assert(quantity_cast<dimensionless<percent>>(50._q_m / 100._q_m).count() == 50);
static_assert(quantity_cast<dim_one, percent>(50._q_m / 100._q_m).count() == 50);
#else
static_assert(quantity_cast<percent>(50._q_m / 100._q_m).count() == 50);
#endif