diff --git a/example/custom_systems.cpp b/example/custom_systems.cpp index 9fe72f4e..c708bf0f 100644 --- a/example/custom_systems.cpp +++ b/example/custom_systems.cpp @@ -84,14 +84,14 @@ void conversions() void unknown_dimensions() { constexpr auto fps_yard = fps::length(1.); - constexpr auto fps_area = quantity_cast(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(fps_area) << "\n"; constexpr auto si_fps_yard = si::fps::length(1.); - constexpr auto si_fps_area = quantity_cast(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(si_fps_area) << "\n"; } std::ostream& operator<<(std::ostream& os, const ratio& r) { return os << "ratio{" << r.num << ", " << r.den << "}"; } diff --git a/src/core/include/units/base_dimension.h b/src/core/include/units/base_dimension.h index 7515d97b..0af40adb 100644 --- a/src/core/include/units/base_dimension.h +++ b/src/core/include/units/base_dimension.h @@ -54,6 +54,7 @@ template 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 diff --git a/src/core/include/units/bits/absolute_magnitude.h b/src/core/include/units/bits/absolute_magnitude.h index 2d9703e3..0216313f 100644 --- a/src/core/include/units/bits/absolute_magnitude.h +++ b/src/core/include/units/bits/absolute_magnitude.h @@ -42,7 +42,7 @@ namespace units::detail { template constexpr Magnitude auto absolute_magnitude(exponent_list) { - return (pow(Es::dimension::base_unit::mag) * ... * magnitude<>{}); + return (magnitude<>{} * ... * pow(Es::dimension::base_unit::mag)); } } // namespace units::detail diff --git a/src/core/include/units/bits/common_type.h b/src/core/include/units/bits/common_type.h index 46f7cb5f..8955d5ab 100644 --- a/src/core/include/units/bits/common_type.h +++ b/src/core/include/units/bits/common_type.h @@ -66,15 +66,13 @@ struct common_quantity_reference_impl, reference> { template struct common_quantity_reference_impl, reference> { + static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = common_magnitude(reference::mag, + reference::mag); using dimension = conditional, 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; + using unit = downcast_unit; using type = reference; }; - template Q2> using common_quantity_reference = TYPENAME detail::common_quantity_reference_impl, diff --git a/src/core/include/units/bits/derived_scaled_unit.h b/src/core/include/units/bits/derived_scaled_unit.h index ecdaf48f..d62b6f45 100644 --- a/src/core/include/units/bits/derived_scaled_unit.h +++ b/src/core/include/units/bits/derived_scaled_unit.h @@ -39,7 +39,7 @@ inline constexpr bool compatible_units, Us...> = (UnitOf constexpr Magnitude auto derived_mag(exponent_list) { - return (mag<1>() * ... * pow(Us::mag / dimension_unit::mag)); + return (magnitude<>{} * ... * pow(Us::mag / dimension_unit::mag)); } template diff --git a/src/core/include/units/bits/dimension_op.h b/src/core/include/units/bits/dimension_op.h index 88580625..820fbc82 100644 --- a/src/core/include/units/bits/dimension_op.h +++ b/src/core/include/units/bits/dimension_op.h @@ -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 -struct unknown_dimension : derived_dimension, unknown_coherent_unit, Es...> {}; +struct unknown_dimension : derived_dimension, unknown_coherent_unit, Es...> {}; namespace detail { diff --git a/src/core/include/units/bits/equivalent.h b/src/core/include/units/bits/equivalent.h index 5bdac612..2fa174ba 100644 --- a/src/core/include/units/bits/equivalent.h +++ b/src/core/include/units/bits/equivalent.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include namespace units { @@ -72,8 +73,7 @@ struct equivalent_impl : // additionally accounts for unknown dimensions template struct equivalent_unit : - std::disjunction, - std::bool_constant::mag == U2::mag / dimension_unit::mag>> {}; + std::disjunction, std::bool_constant::mag == reference::mag>> {}; // point origins diff --git a/src/core/include/units/bits/quantity_of.h b/src/core/include/units/bits/quantity_of.h index ef7e8d77..1e53d22b 100644 --- a/src/core/include/units/bits/quantity_of.h +++ b/src/core/include/units/bits/quantity_of.h @@ -37,9 +37,10 @@ inline constexpr bool same_exponents_of = false; template typename DimTemplate> inline constexpr bool same_exponents_of, DimTemplate> = - requires { typename DimTemplate, unknown_coherent_unit, typename Es::dimension...>; } && - std::same_as, typename DimTemplate, unknown_coherent_unit, - typename Es::dimension...>::recipe>; + requires { + typename DimTemplate, unknown_coherent_unit, typename Es::dimension...>; + }&& std::same_as, typename DimTemplate, unknown_coherent_unit, + typename Es::dimension...>::recipe>; } // namespace detail diff --git a/src/core/include/units/derived_dimension.h b/src/core/include/units/derived_dimension.h index 8033f463..0af2e096 100644 --- a/src/core/include/units/derived_dimension.h +++ b/src/core/include/units/derived_dimension.h @@ -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 struct derived_dimension : downcast_dispatch> { using recipe = exponent_list; 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 diff --git a/src/core/include/units/quantity_cast.h b/src/core/include/units/quantity_cast.h index fdb90aef..5295f3a1 100644 --- a/src/core/include/units/quantity_cast.h +++ b/src/core/include/units/quantity_cast.h @@ -28,6 +28,7 @@ #include #include #include +#include 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 -inline constexpr Magnitude auto quantity_magnitude = std::enable_if_t, magnitude<>>{}; - -template -inline constexpr Magnitude auto quantity_magnitude> = [] { - if constexpr (BaseDimension) { - return U::mag; - } else { - return D::base_units_ratio * U::mag / D::coherent_unit::mag; - } -}(); +template +inline constexpr Magnitude auto quantity_magnitude = decltype(Q::reference)::mag; template inline constexpr ratio quantity_ratio = as_ratio(quantity_magnitude); @@ -79,8 +71,8 @@ template struct cast_traits; template - requires common_type_with_, - std::intmax_t> struct cast_traits { + requires common_type_with_, std::intmax_t> +struct cast_traits { using ratio_type = std::common_type_t, std::intmax_t>; using rep_type = ratio_type; }; diff --git a/src/core/include/units/reference.h b/src/core/include/units/reference.h index 200cc2fb..c6a68fb1 100644 --- a/src/core/include/units/reference.h +++ b/src/core/include/units/reference.h @@ -35,27 +35,21 @@ struct reference; namespace detail { -template -using reference_multiply_impl = - reference::mag) * (U2::mag / dimension_unit::mag) * - dimension_unit::mag>>; +template +using reference_multiply_impl = reference>; -template -using reference_divide_impl = - reference::mag) / (U2::mag / dimension_unit::mag) * - dimension_unit::mag>>; +template +using reference_divide_impl = reference>; } // namespace detail template using reference_multiply = - detail::reference_multiply_impl, - typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>; + detail::reference_multiply_impl, R1, R2>; template using reference_divide = - detail::reference_divide_impl, - typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>; + detail::reference_divide_impl, R1, R2>; /** * @brief The type for quantity references @@ -100,6 +94,7 @@ template 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 diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index 59e8c327..dbba2ecf 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -24,6 +24,7 @@ #include #include +#include // IWYU pragma: begin_exports #include @@ -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 struct scaled_unit : downcast_base> { 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 {}; +template +struct unknown_coherent_unit : + downcast_dispatch, + scaled_unit()), unknown_coherent_unit>> {}; namespace detail { diff --git a/test/unit_test/static/dimensions_concepts_test.cpp b/test/unit_test/static/dimensions_concepts_test.cpp index 2b237250..f96a11dc 100644 --- a/test/unit_test/static/dimensions_concepts_test.cpp +++ b/test/unit_test/static/dimensions_concepts_test.cpp @@ -58,7 +58,8 @@ static_assert(!Area>); static_assert(Volume>); static_assert(!Volume>); #if UNITS_DOWNCAST_MODE == 0 -static_assert(Volume>, unknown_coherent_unit>>); +static_assert( + Volume>, unknown_coherent_unit>>>); #endif static_assert(Speed>); @@ -68,21 +69,23 @@ static_assert(Acceleration>); static_assert(!Acceleration>); #if UNITS_DOWNCAST_MODE == 0 static_assert(Acceleration, exponent>, - unknown_coherent_unit>>); + unknown_coherent_unit, exponent>>>); #endif static_assert(Force>); static_assert(!Force>); #if UNITS_DOWNCAST_MODE == 0 // static_assert(Force, exponent, -// exponent>, unknown_coherent_unit>>); +// exponent>, unknown_coherent_unit, +// exponent>>); #endif static_assert(Energy>); static_assert(!Energy>); #if UNITS_DOWNCAST_MODE == 0 // static_assert(Energy, exponent, -// exponent>, unknown_coherent_unit>>); +// exponent>, unknown_coherent_unit, +// exponent>>); #endif static_assert(Power>); diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index d631d1a6..f510e2b4 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -581,21 +581,26 @@ static_assert(is_same_v>); static_assert(compare(), metre>, std::int64_t>>); static_assert( - compare, exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + compare, exponent>, + scaled_unit(), unknown_coherent_unit, exponent>>, + std::int64_t>>); static_assert(compare>); static_assert(compare(), hertz>, std::int64_t>>); static_assert(compare>); static_assert( - compare>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + compare>, + scaled_unit(), unknown_coherent_unit>>, std::int64_t>>); static_assert(compare(), one>, std::int64_t>>); static_assert(compare>); static_assert( compare(), metre_per_second>, std::int64_t>>); static_assert( - compare, exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); + compare, exponent>, + scaled_unit(), unknown_coherent_unit, exponent>>, + 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(2_q_dm3)), volume, units::exponent>, - scaled_unit(), unknown_coherent_unit>, std::int64_t>>); +static_assert( + is_same_v, units::exponent>, + scaled_unit(), + unknown_coherent_unit, units::exponent>>, + std::int64_t>>); static_assert(is_same_v(), metre>, std::int64_t>>); #else diff --git a/test/unit_test/static/si_cgs_test.cpp b/test/unit_test/static/si_cgs_test.cpp index 42e91ad8..01f4379e 100644 --- a/test/unit_test/static/si_cgs_test.cpp +++ b/test/unit_test/static/si_cgs_test.cpp @@ -116,7 +116,7 @@ static_assert(si::length(1) + quantity_cast>(10 static_assert(100_q_cm + quantity_cast>(si::length(1)) == 200_q_cm); static_assert(quantity_cast>(si::length(1)) + 100_q_cm == 200_q_cm); -// substraction +// subtraction static_assert(500_q_cm - si::length(1) == si::length(4)); static_assert(si::length(5) - 100_q_cm == si::length(4)); @@ -150,6 +150,23 @@ static_assert(si::area(4) / quantity_cast>(si::area(4)) / 200._q_cm == 200_q_cm); +static_assert(si::cgs::length(50) == si::length(50)); +static_assert(si::cgs::mass(50) == si::mass(50)); + +static_assert(1 / si::cgs::length(50) == 1 / si::length(50)); +static_assert(1 / si::cgs::length(50) == 1 / si::length(50)); + +static_assert(1 / si::cgs::mass(50) == 1 / si::mass(50)); +static_assert(1 / si::cgs::mass(50) == 1 / si::mass(50)); + +static_assert(si::cgs::length(50) * si::cgs::mass(50) == + si::length(50) * si::mass(50)); +static_assert(si::cgs::length(50) * si::cgs::mass(50) == + si::length(50) * si::mass(50)); + +static_assert(si::cgs::length(50) / si::cgs::mass(50) == + si::length(50) / si::mass(50)); + } // namespace cgs_test } // namespace