fix: unknown_coherent_unit fixed

This commit is contained in:
Mateusz Pusz
2022-08-01 11:59:00 +02:00
parent bb5c02e09e
commit 0ebf85b9db
15 changed files with 82 additions and 62 deletions

View File

@ -84,14 +84,14 @@ void conversions()
void unknown_dimensions()
{
constexpr auto fps_yard = fps::length<fps::yard>(1.);
constexpr auto fps_area = quantity_cast<unknown_coherent_unit>(fps_yard * fps_yard);
constexpr auto fps_area = fps_yard * fps_yard;
std::cout << fps_yard << "\n";
std::cout << fps_area << "\n";
std::cout << quantity_cast<decltype(fps_area)::dimension::coherent_unit>(fps_area) << "\n";
constexpr auto si_fps_yard = si::fps::length<si::fps::yard>(1.);
constexpr auto si_fps_area = quantity_cast<unknown_coherent_unit>(si_fps_yard * si_fps_yard);
constexpr auto si_fps_area = si_fps_yard * si_fps_yard;
std::cout << si_fps_yard << "\n";
std::cout << si_fps_area << "\n";
std::cout << quantity_cast<decltype(si_fps_area)::dimension::coherent_unit>(si_fps_area) << "\n";
}
std::ostream& operator<<(std::ostream& os, const ratio& r) { return os << "ratio{" << r.num << ", " << r.den << "}"; }

View File

@ -54,6 +54,7 @@ template<basic_fixed_string Symbol, NamedUnit U>
struct base_dimension {
static constexpr auto symbol = Symbol; ///< Unique base dimension identifier
using base_unit = U; ///< Base unit adopted for this dimension
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = magnitude{};
};
// base_dimension_less

View File

@ -42,7 +42,7 @@ namespace units::detail {
template<typename... Es>
constexpr Magnitude auto absolute_magnitude(exponent_list<Es...>)
{
return (pow<ratio{Es::num, Es::den}>(Es::dimension::base_unit::mag) * ... * magnitude<>{});
return (magnitude<>{} * ... * pow<ratio{Es::num, Es::den}>(Es::dimension::base_unit::mag));
}
} // namespace units::detail

View File

@ -66,15 +66,13 @@ struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
template<typename D1, typename U1, typename D2, typename U2>
struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = common_magnitude(reference<D1, U1>::mag,
reference<D2, U2>::mag);
using dimension = conditional<is_specialization_of<D1, unknown_dimension>, D2, D1>;
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto m1 = D1::base_units_ratio * U1::mag;
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto m2 = D2::base_units_ratio * U2::mag;
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto cm = common_magnitude(m1, m2);
using unit = downcast_unit<dimension, cm / dimension::base_units_ratio>;
using unit = downcast_unit<dimension, mag / dimension::mag>;
using type = reference<dimension, unit>;
};
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
using common_quantity_reference =
TYPENAME detail::common_quantity_reference_impl<std::remove_const_t<decltype(Q1::reference)>,

View File

@ -39,7 +39,7 @@ inline constexpr bool compatible_units<exponent_list<Es...>, Us...> = (UnitOf<Us
template<Unit... Us, typename... Es>
constexpr Magnitude auto derived_mag(exponent_list<Es...>)
{
return (mag<1>() * ... * pow<ratio{Es::num, Es::den}>(Us::mag / dimension_unit<typename Es::dimension>::mag));
return (magnitude<>{} * ... * pow<ratio{Es::num, Es::den}>(Us::mag / dimension_unit<typename Es::dimension>::mag));
}
template<DerivedDimension D, Unit... Us>

View File

@ -37,12 +37,12 @@ namespace units {
*
* Sometimes a temporary partial result of a complex calculation may not result in a predefined
* dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_coherent_unit`
* and ratio(1).
* with a magnitude being the absolute one of all the exponents of such a dimension.
*
* @tparam Es the list of exponents of ingredient dimensions
*/
template<Exponent... Es>
struct unknown_dimension : derived_dimension<unknown_dimension<Es...>, unknown_coherent_unit, Es...> {};
struct unknown_dimension : derived_dimension<unknown_dimension<Es...>, unknown_coherent_unit<Es...>, Es...> {};
namespace detail {

View File

@ -23,6 +23,7 @@
#pragma once
#include <units/bits/basic_concepts.h>
#include <units/reference.h>
#include <units/unit.h>
namespace units {
@ -72,8 +73,7 @@ struct equivalent_impl<D1, D2> :
// additionally accounts for unknown dimensions
template<Unit U1, Dimension D1, Unit U2, Dimension D2>
struct equivalent_unit :
std::disjunction<equivalent_impl<U1, U2>,
std::bool_constant<U1::mag / dimension_unit<D1>::mag == U2::mag / dimension_unit<D2>::mag>> {};
std::disjunction<equivalent_impl<U1, U2>, std::bool_constant<reference<D1, U1>::mag == reference<D2, U2>::mag>> {};
// point origins

View File

@ -37,9 +37,10 @@ inline constexpr bool same_exponents_of = false;
template<Exponent... Es, template<typename...> typename DimTemplate>
inline constexpr bool same_exponents_of<unknown_dimension<Es...>, DimTemplate> =
requires { typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit, typename Es::dimension...>; } &&
std::same_as<exponent_list<Es...>, typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit,
typename Es::dimension...>::recipe>;
requires {
typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit<Es...>, typename Es::dimension...>;
}&& std::same_as<exponent_list<Es...>, typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit<Es...>,
typename Es::dimension...>::recipe>;
} // namespace detail

View File

@ -72,8 +72,8 @@ using make_dimension = TYPENAME to_derived_dimension_base<
* and in CGS barye. Those two units are not directly related with each other with some ratio. As they both are
* coherent units of their dimensions, the ratio between them is directly determined by the ratios of base units
* defined in base dimensions end their exponents in the derived dimension recipe. To provide interoperability of
* such quantities of different systems base_units_ratio is being used. The result of the division of two
* base_units_ratio of two quantities of equivalent dimensions in two different systems gives a ratio between their
* such quantities of different systems mag is being used. The result of the division of two
* mag of two quantities of equivalent dimensions in two different systems gives a ratio between their
* coherent units. Alternatively, the user would always have to directly define a barye in terms of pascal or vice
* versa.
*
@ -85,8 +85,8 @@ template<typename Child, Unit U, Exponent... Es>
struct derived_dimension : downcast_dispatch<Child, typename detail::make_dimension<Es...>> {
using recipe = exponent_list<Es...>;
using coherent_unit = U;
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto base_units_ratio =
detail::absolute_magnitude(typename derived_dimension::exponents());
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag =
detail::absolute_magnitude(typename derived_dimension::exponents()) / U::mag;
};
} // namespace units

View File

@ -28,6 +28,7 @@
#include <units/concepts.h>
#include <units/customization_points.h>
#include <units/magnitude.h>
#include <units/reference.h>
UNITS_DIAGNOSTIC_PUSH
// warning C4244: 'argument': conversion from 'intmax_t' to 'T', possible loss of data with T=int
@ -49,17 +50,8 @@ class quantity_point_kind;
namespace detail {
template<typename T>
inline constexpr Magnitude auto quantity_magnitude = std::enable_if_t<!Quantity<T>, magnitude<>>{};
template<typename D, typename U, typename Rep>
inline constexpr Magnitude auto quantity_magnitude<quantity<D, U, Rep>> = [] {
if constexpr (BaseDimension<D>) {
return U::mag;
} else {
return D::base_units_ratio * U::mag / D::coherent_unit::mag;
}
}();
template<Quantity Q>
inline constexpr Magnitude auto quantity_magnitude = decltype(Q::reference)::mag;
template<Quantity Q>
inline constexpr ratio quantity_ratio = as_ratio(quantity_magnitude<Q>);
@ -79,8 +71,8 @@ template<typename From, typename To>
struct cast_traits;
template<typename From, typename To>
requires common_type_with_<std::common_type_t<From, To>,
std::intmax_t> struct cast_traits<From, To> {
requires common_type_with_<std::common_type_t<From, To>, std::intmax_t>
struct cast_traits<From, To> {
using ratio_type = std::common_type_t<std::common_type_t<From, To>, std::intmax_t>;
using rep_type = ratio_type;
};

View File

@ -35,27 +35,21 @@ struct reference;
namespace detail {
template<typename D, typename D1, typename U1, typename D2, typename U2>
using reference_multiply_impl =
reference<D, downcast_unit<D, (U1::mag / dimension_unit<D1>::mag) * (U2::mag / dimension_unit<D2>::mag) *
dimension_unit<D>::mag>>;
template<Dimension D, Reference R1, Reference R2>
using reference_multiply_impl = reference<D, downcast_unit<D, R1::mag * R2::mag / D::mag>>;
template<typename D, typename D1, typename U1, typename D2, typename U2>
using reference_divide_impl =
reference<D, downcast_unit<D, (U1::mag / dimension_unit<D1>::mag) / (U2::mag / dimension_unit<D2>::mag) *
dimension_unit<D>::mag>>;
template<typename D, Reference R1, Reference R2>
using reference_divide_impl = reference<D, downcast_unit<D, R1::mag / R2::mag / D::mag>>;
} // namespace detail
template<Reference R1, Reference R2>
using reference_multiply =
detail::reference_multiply_impl<dimension_multiply<typename R1::dimension, typename R2::dimension>,
typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>;
detail::reference_multiply_impl<dimension_multiply<typename R1::dimension, typename R2::dimension>, R1, R2>;
template<Reference R1, Reference R2>
using reference_divide =
detail::reference_divide_impl<dimension_divide<typename R1::dimension, typename R2::dimension>,
typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>;
detail::reference_divide_impl<dimension_divide<typename R1::dimension, typename R2::dimension>, R1, R2>;
/**
* @brief The type for quantity references
@ -100,6 +94,7 @@ template<Dimension D, UnitOf<D> U>
struct reference {
using dimension = D;
using unit = U;
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = dimension::mag * unit::mag;
// Hidden Friends
// Below friend functions are to be found via argument-dependent lookup only

View File

@ -24,6 +24,7 @@
#include <units/bits/derived_symbol_text.h>
#include <units/bits/external/downcasting.h>
#include <units/bits/external/type_traits.h>
// IWYU pragma: begin_exports
#include <units/bits/derived_scaled_unit.h>
@ -58,6 +59,7 @@ inline constexpr bool can_be_prefixed = false;
* @tparam M a Magnitude representing the (relative) size of this unit
* @tparam U a unit to use as a reference for this dimension
*/
// TODO Replace `typename` with `Unit`
template<Magnitude auto M, typename U>
struct scaled_unit : downcast_base<scaled_unit<M, U>> {
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M;
@ -188,7 +190,10 @@ struct prefixed_alias_unit : U {
*
* Used as a coherent unit of an unknown dimension.
*/
struct unknown_coherent_unit : derived_unit<unknown_coherent_unit> {};
template<Exponent... Es>
struct unknown_coherent_unit :
downcast_dispatch<unknown_coherent_unit<Es...>,
scaled_unit<detail::absolute_magnitude(exponent_list<Es...>()), unknown_coherent_unit<Es...>>> {};
namespace detail {

View File

@ -58,7 +58,8 @@ static_assert(!Area<si::time<si::second>>);
static_assert(Volume<si::volume<si::cubic_metre>>);
static_assert(!Volume<si::area<si::square_metre>>);
#if UNITS_DOWNCAST_MODE == 0
static_assert(Volume<quantity<unknown_dimension<exponent<si::dim_length, 3>>, unknown_coherent_unit>>);
static_assert(
Volume<quantity<unknown_dimension<exponent<si::dim_length, 3>>, unknown_coherent_unit<exponent<si::dim_length, 3>>>>);
#endif
static_assert(Speed<si::speed<si::metre_per_second>>);
@ -68,21 +69,23 @@ static_assert(Acceleration<si::acceleration<si::metre_per_second_sq>>);
static_assert(!Acceleration<si::time<si::second>>);
#if UNITS_DOWNCAST_MODE == 0
static_assert(Acceleration<quantity<unknown_dimension<exponent<si::dim_length, 1>, exponent<si::dim_time, -2>>,
unknown_coherent_unit>>);
unknown_coherent_unit<exponent<si::dim_length, 1>, exponent<si::dim_time, -2>>>>);
#endif
static_assert(Force<si::force<si::newton>>);
static_assert(!Force<si::time<si::second>>);
#if UNITS_DOWNCAST_MODE == 0
// static_assert(Force<quantity<unknown_dimension<exponent<si::dim_length, 1>, exponent<si::dim_time, -2>,
// exponent<si::dim_mass, 1>>, unknown_coherent_unit>>);
// exponent<si::dim_mass, 1>>, unknown_coherent_unit<exponent<si::dim_length, 1>,
// exponent<si::dim_time, -2>>>);
#endif
static_assert(Energy<si::energy<si::joule>>);
static_assert(!Energy<si::time<si::second>>);
#if UNITS_DOWNCAST_MODE == 0
// static_assert(Energy<quantity<unknown_dimension<exponent<si::dim_mass, 1>, exponent<si::dim_length, 2>,
// exponent<si::dim_time, -3>>, unknown_coherent_unit>>);
// exponent<si::dim_time, -3>>, unknown_coherent_unit<exponent<si::dim_mass, 1>,
// exponent<si::dim_length, 2>>>);
#endif
static_assert(Power<si::power<si::watt>>);

View File

@ -581,21 +581,26 @@ static_assert(is_same_v<decltype(1_q_km % 1_q_m), length<kilometre, std::int64_t
static_assert(compare<decltype(1_q_m_per_s * 1_q_s), length<metre, std::int64_t>>);
static_assert(compare<decltype(1_q_m_per_s * 1_q_h), length<scaled_unit<mag<3600>(), metre>, std::int64_t>>);
static_assert(
compare<decltype(1_q_m * 1_q_min), quantity<unknown_dimension<exponent<dim_length, 1>, exponent<dim_time, 1>>,
scaled_unit<mag<60>(), unknown_coherent_unit>, std::int64_t>>);
compare<decltype(1_q_m * 1_q_min),
quantity<unknown_dimension<exponent<dim_length, 1>, exponent<dim_time, 1>>,
scaled_unit<mag<60>(), unknown_coherent_unit<exponent<dim_length, 1>, exponent<dim_time, 1>>>,
std::int64_t>>);
static_assert(compare<decltype(1_q_s * 1_q_Hz), dimensionless<one, std::int64_t>>);
static_assert(compare<decltype(1 / 1_q_min), frequency<scaled_unit<mag<ratio(1, 60)>(), hertz>, std::int64_t>>);
static_assert(compare<decltype(1 / 1_q_Hz), isq::si::time<second, std::int64_t>>);
static_assert(
compare<decltype(1 / 1_q_km), quantity<unknown_dimension<exponent<dim_length, -1>>,
scaled_unit<mag<ratio(1, 1000)>(), unknown_coherent_unit>, std::int64_t>>);
compare<decltype(1 / 1_q_km),
quantity<unknown_dimension<exponent<dim_length, -1>>,
scaled_unit<mag<ratio(1, 1000)>(), unknown_coherent_unit<exponent<dim_length, -1>>>, std::int64_t>>);
static_assert(compare<decltype(1_q_km / 1_q_m), dimensionless<scaled_unit<mag<1000>(), one>, std::int64_t>>);
static_assert(compare<decltype(1_q_m / 1_q_s), speed<metre_per_second, std::int64_t>>);
static_assert(
compare<decltype(1_q_m / 1_q_min), speed<scaled_unit<mag<ratio(1, 60)>(), metre_per_second>, std::int64_t>>);
static_assert(
compare<decltype(1_q_min / 1_q_m), quantity<unknown_dimension<exponent<dim_length, -1>, exponent<dim_time, 1>>,
scaled_unit<mag<60>(), unknown_coherent_unit>, std::int64_t>>);
compare<decltype(1_q_min / 1_q_m),
quantity<unknown_dimension<exponent<dim_length, -1>, exponent<dim_time, 1>>,
scaled_unit<mag<60>(), unknown_coherent_unit<exponent<dim_length, -1>, exponent<dim_time, 1>>>,
std::int64_t>>);
static_assert((1_q_m + 1_q_m).number() == 2);
static_assert((1_q_m + 1_q_km).number() == 1001);
@ -883,9 +888,12 @@ static_assert(!is_same_v<decltype(quantity_cast<litre>(2_q_dm3)), volume<cubic_d
#if UNITS_DOWNCAST_MODE == 0
static_assert(is_same_v<decltype(10_q_m / 5_q_s),
quantity<unknown_dimension<units::exponent<dim_length, 1>, units::exponent<dim_time, -1>>,
scaled_unit<mag<1>(), unknown_coherent_unit>, std::int64_t>>);
static_assert(
is_same_v<decltype(10_q_m / 5_q_s),
quantity<unknown_dimension<units::exponent<dim_length, 1>, units::exponent<dim_time, -1>>,
scaled_unit<mag<1>(),
unknown_coherent_unit<units::exponent<dim_length, 1>, units::exponent<dim_time, -1>>>,
std::int64_t>>);
static_assert(is_same_v<decltype(1_q_mm + 1_q_km), length<scaled_unit<mag<ratio(1, 1000)>(), metre>, std::int64_t>>);
#else

View File

@ -116,7 +116,7 @@ static_assert(si::length<si::metre>(1) + quantity_cast<si::length<si::metre>>(10
static_assert(100_q_cm + quantity_cast<si::cgs::length<si::cgs::centimetre>>(si::length<si::metre>(1)) == 200_q_cm);
static_assert(quantity_cast<si::cgs::length<si::cgs::centimetre>>(si::length<si::metre>(1)) + 100_q_cm == 200_q_cm);
// substraction
// subtraction
static_assert(500_q_cm - si::length<si::metre>(1) == si::length<si::metre>(4));
static_assert(si::length<si::metre>(5) - 100_q_cm == si::length<si::metre>(4));
@ -150,6 +150,23 @@ static_assert(si::area<si::square_metre>(4) / quantity_cast<si::length<si::metre
static_assert(quantity_cast<si::cgs::area<si::cgs::square_centimetre>>(si::area<si::square_metre>(4)) / 200._q_cm ==
200_q_cm);
static_assert(si::cgs::length<si::cgs::centimetre>(50) == si::length<si::centimetre>(50));
static_assert(si::cgs::mass<si::cgs::gram>(50) == si::mass<si::gram>(50));
static_assert(1 / si::cgs::length<si::cgs::centimetre>(50) == 1 / si::length<si::centimetre>(50));
static_assert(1 / si::cgs::length<si::metre>(50) == 1 / si::length<si::metre>(50));
static_assert(1 / si::cgs::mass<si::cgs::gram>(50) == 1 / si::mass<si::gram>(50));
static_assert(1 / si::cgs::mass<si::kilogram>(50) == 1 / si::mass<si::kilogram>(50));
static_assert(si::cgs::length<si::cgs::centimetre>(50) * si::cgs::mass<si::cgs::gram>(50) ==
si::length<si::centimetre>(50) * si::mass<si::gram>(50));
static_assert(si::cgs::length<si::metre>(50) * si::cgs::mass<si::kilogram>(50) ==
si::length<si::metre>(50) * si::mass<si::kilogram>(50));
static_assert(si::cgs::length<si::cgs::centimetre>(50) / si::cgs::mass<si::cgs::gram>(50) ==
si::length<si::centimetre>(50) / si::mass<si::gram>(50));
} // namespace cgs_test
} // namespace