From d19b2803ceba94ecbab15b604e21d21e5557158f Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Sat, 9 Apr 2022 17:55:44 +0000 Subject: [PATCH] Migrate units from ratio to Magnitude This commit is huge, but hopefully the cognitive load is not too bad. The bulk of this commit is just some fairly mechanical updates from `ratio` to `Magnitude`. Other things to call out: - `UnitRatio` goes away. We don't need this concept, because Magnitude can't even _represent_ anything that doesn't satisfy it. - I commented out some formatting test cases where the precise expression changes, but the number is completely equivalent. We will need to decide how we want to handle Magnitude formatting as a separate, follow-on task. But at least Magnitude gives us all the tools we'll need to do so! --- example/custom_systems.cpp | 6 +-- example/literals/custom_systems.cpp | 6 +-- .../include/units/bits/base_units_ratio.h | 10 ----- src/core/include/units/bits/basic_concepts.h | 17 ++------ src/core/include/units/bits/common_type.h | 12 +++--- src/core/include/units/bits/derived_unit.h | 6 --- src/core/include/units/chrono.h | 4 +- src/core/include/units/derived_dimension.h | 3 +- .../include/units/generic/dimensionless.h | 2 +- src/core/include/units/math.h | 6 +-- src/core/include/units/prefix.h | 2 + src/core/include/units/quantity.h | 2 +- src/core/include/units/quantity_cast.h | 43 +++++++++---------- src/core/include/units/reference.h | 8 ++-- src/core/include/units/unit.h | 30 ++++++------- .../units/isq/iec80000/storage_capacity.h | 2 +- .../si-fps/include/units/isq/si/fps/force.h | 3 +- .../si-fps/include/units/isq/si/fps/length.h | 14 +++--- .../si-fps/include/units/isq/si/fps/mass.h | 19 ++++---- .../si-fps/include/units/isq/si/fps/power.h | 3 +- .../include/units/isq/si/fps/pressure.h | 5 ++- .../si-hep/include/units/isq/si/hep/area.h | 2 +- .../si-hep/include/units/isq/si/hep/mass.h | 15 +++++-- .../include/units/isq/si/hep/momentum.h | 2 +- .../si-iau/include/units/isq/si/iau/length.h | 6 +-- .../include/units/isq/si/imperial/length.h | 4 +- .../units/isq/si/international/length.h | 14 +++--- .../include/units/isq/si/typographic/length.h | 12 ++++-- .../include/units/isq/si/uscs/length.h | 6 +-- .../include/units/isq/si/catalytic_activity.h | 2 +- src/systems/si/include/units/isq/si/energy.h | 3 +- src/systems/si/include/units/isq/si/length.h | 3 +- .../include/units/isq/si/magnetic_induction.h | 2 +- src/systems/si/include/units/isq/si/mass.h | 3 +- src/systems/si/include/units/isq/si/time.h | 6 +-- test/unit_test/runtime/fmt_test.cpp | 10 +++-- test/unit_test/runtime/fmt_units_test.cpp | 17 +++++--- test/unit_test/static/concepts_test.cpp | 9 ---- test/unit_test/static/quantity_kind_test.cpp | 6 +-- test/unit_test/static/quantity_test.cpp | 37 +++++++++------- test/unit_test/static/si_test.cpp | 4 +- test/unit_test/static/unit_test.cpp | 30 +++++++------ 42 files changed, 197 insertions(+), 199 deletions(-) diff --git a/example/custom_systems.cpp b/example/custom_systems.cpp index f8dfd28f..ecb5f0d4 100644 --- a/example/custom_systems.cpp +++ b/example/custom_systems.cpp @@ -33,7 +33,7 @@ using namespace units; namespace fps { struct foot : named_unit {}; -struct yard : named_scaled_unit {}; +struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; @@ -54,8 +54,8 @@ using length = quantity; namespace fps { -struct foot : named_scaled_unit {}; -struct yard : named_scaled_unit {}; +struct foot : named_scaled_unit(), metre> {}; +struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; diff --git a/example/literals/custom_systems.cpp b/example/literals/custom_systems.cpp index f8fa8a3b..d0f80915 100644 --- a/example/literals/custom_systems.cpp +++ b/example/literals/custom_systems.cpp @@ -33,7 +33,7 @@ using namespace units; namespace fps { struct foot : named_unit {}; -struct yard : named_scaled_unit {}; +struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; @@ -54,8 +54,8 @@ using length = quantity; namespace fps { -struct foot : named_scaled_unit {}; -struct yard : named_scaled_unit {}; +struct foot : named_scaled_unit(), metre> {}; +struct yard : named_scaled_unit(), foot> {}; struct dim_length : base_dimension<"L", foot> {}; diff --git a/src/core/include/units/bits/base_units_ratio.h b/src/core/include/units/bits/base_units_ratio.h index dad86a67..2d9703e3 100644 --- a/src/core/include/units/bits/base_units_ratio.h +++ b/src/core/include/units/bits/base_units_ratio.h @@ -45,14 +45,4 @@ constexpr Magnitude auto absolute_magnitude(exponent_list) return (pow(Es::dimension::base_unit::mag) * ... * magnitude<>{}); } -/** - * @brief Calculates the common ratio of all the references of base units in the derived dimension - */ -template -constexpr ratio base_units_ratio(exponent_list es) -{ - return as_ratio(absolute_magnitude(es)); -} - - } // namespace units::detail diff --git a/src/core/include/units/bits/basic_concepts.h b/src/core/include/units/bits/basic_concepts.h index ecff7a2f..54f328aa 100644 --- a/src/core/include/units/bits/basic_concepts.h +++ b/src/core/include/units/bits/basic_concepts.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include // IWYU pragma: end_exports #include @@ -67,24 +67,15 @@ void to_prefix_base(const volatile prefix_base*); template concept Prefix = requires(T* t) { detail::to_prefix_base(t); }; -/** - * @brief A concept matching unit's ratio - * - * Satisfied by all ratio values for which `R.num > 0` and `R.den > 0`. - */ -template -concept UnitRatio = (R.num > 0) && (R.den > 0); - // Unit -template - requires UnitRatio +template struct scaled_unit; // TODO: Remove when P1985 accepted namespace detail { -template -void to_base_scaled_unit(const volatile scaled_unit*); +template +void to_base_scaled_unit(const volatile scaled_unit*); } // namespace detail diff --git a/src/core/include/units/bits/common_type.h b/src/core/include/units/bits/common_type.h index 5dd8568b..40880927 100644 --- a/src/core/include/units/bits/common_type.h +++ b/src/core/include/units/bits/common_type.h @@ -55,22 +55,22 @@ struct common_quantity_reference_impl, reference> { template struct common_quantity_reference_impl, reference> { - using type = reference>; + using type = reference>; }; template requires(same_unit_reference, dimension_unit>::value) struct common_quantity_reference_impl, reference> { - using type = reference>; + using type = reference>; }; template struct common_quantity_reference_impl, reference> { using dimension = conditional, D2, D1>; - static constexpr ratio r1 = D1::base_units_ratio * U1::ratio; - static constexpr ratio r2 = D2::base_units_ratio * U2::ratio; - static constexpr ratio cr = common_ratio(r1, r2); - using unit = downcast_unit; + static constexpr Magnitude auto m1 = D1::base_units_ratio * U1::mag; + static constexpr Magnitude auto m2 = D2::base_units_ratio * U2::mag; + static constexpr Magnitude auto cm = common_magnitude(m1, m2); + using unit = downcast_unit; using type = reference; }; diff --git a/src/core/include/units/bits/derived_unit.h b/src/core/include/units/bits/derived_unit.h index 01ebbf23..61a83986 100644 --- a/src/core/include/units/bits/derived_unit.h +++ b/src/core/include/units/bits/derived_unit.h @@ -43,12 +43,6 @@ constexpr Magnitude auto derived_mag(exponent_list) pow(Us::mag / dimension_unit::mag)); } -template -constexpr ratio derived_ratio(exponent_list es) -{ - return as_ratio(derived_mag(es)); -} - template using derived_unit = scaled_unit(typename D::recipe()), typename D::coherent_unit::reference>; diff --git a/src/core/include/units/chrono.h b/src/core/include/units/chrono.h index d19660de..f5be9ea0 100644 --- a/src/core/include/units/chrono.h +++ b/src/core/include/units/chrono.h @@ -34,7 +34,7 @@ namespace units { template struct quantity_like_traits> { using dimension = isq::si::dim_time; - using unit = downcast_unit; + using unit = downcast_unit()>; using rep = Rep; [[nodiscard]] static constexpr rep number(const std::chrono::duration& q) { return q.count(); } }; @@ -45,7 +45,7 @@ struct clock_origin : point_origin {}; template struct quantity_point_like_traits>> { using origin = clock_origin; - using unit = downcast_unit; + using unit = downcast_unit()>; using rep = Rep; [[nodiscard]] static constexpr auto relative(const std::chrono::time_point>& qp) { diff --git a/src/core/include/units/derived_dimension.h b/src/core/include/units/derived_dimension.h index 0ea8f23a..76c8dc9f 100644 --- a/src/core/include/units/derived_dimension.h +++ b/src/core/include/units/derived_dimension.h @@ -85,7 +85,8 @@ template struct derived_dimension : downcast_dispatch> { using recipe = exponent_list; using coherent_unit = U; - static constexpr ratio base_units_ratio = detail::base_units_ratio(typename derived_dimension::exponents()); + static constexpr Magnitude auto base_units_ratio = + detail::absolute_magnitude(typename derived_dimension::exponents()); }; } // namespace units diff --git a/src/core/include/units/generic/dimensionless.h b/src/core/include/units/generic/dimensionless.h index d1d34c2e..ee96af8e 100644 --- a/src/core/include/units/generic/dimensionless.h +++ b/src/core/include/units/generic/dimensionless.h @@ -31,7 +31,7 @@ namespace units { struct one : named_unit {}; -struct percent : named_scaled_unit {}; +struct percent : named_scaled_unit(), one> {}; /** * @brief Dimension one diff --git a/src/core/include/units/math.h b/src/core/include/units/math.h index d2c2728e..0de45139 100644 --- a/src/core/include/units/math.h +++ b/src/core/include/units/math.h @@ -57,7 +57,7 @@ template return rep(1); } else { using dim = dimension_pow; - using unit = downcast_unit(Q::unit::ratio)>; + using unit = downcast_unit(Q::unit::mag)>; using std::pow; return quantity( static_cast(pow(q.number(), static_cast(Num) / static_cast(Den)))); @@ -77,7 +77,7 @@ template requires requires { sqrt(q.number()); } || requires { std::sqrt(q.number()); } { using dim = dimension_pow; - using unit = downcast_unit; + using unit = downcast_unit(Q::unit::mag)>; using rep = TYPENAME Q::rep; using std::sqrt; return quantity(static_cast(sqrt(q.number()))); @@ -96,7 +96,7 @@ template requires requires { cbrt(q.number()); } || requires { std::cbrt(q.number()); } { using dim = dimension_pow; - using unit = downcast_unit; + using unit = downcast_unit(Q::unit::mag)>; using rep = TYPENAME Q::rep; using std::cbrt; return quantity(static_cast(cbrt(q.number()))); diff --git a/src/core/include/units/prefix.h b/src/core/include/units/prefix.h index 0a9386d1..7b9b3305 100644 --- a/src/core/include/units/prefix.h +++ b/src/core/include/units/prefix.h @@ -25,6 +25,7 @@ #include #include // IWYU pragma: begin_exports +#include #include #include // IWYU pragma: end_exports @@ -52,6 +53,7 @@ template struct prefix_base : downcast_base> { using prefix_family = PF; static constexpr ::units::ratio ratio = R; + static constexpr Magnitude auto mag = as_magnitude(); }; } // namespace detail diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index 9eb2722b..de2741d8 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -402,7 +402,7 @@ public: { gsl_ExpectsAudit(q.number() != quantity_values::zero()); using dim = dim_invert; - using ret_unit = downcast_unit; + using ret_unit = downcast_unit(U::mag)>; using ret = quantity, Value, rep>>; return ret(v / q.number()); } diff --git a/src/core/include/units/quantity_cast.h b/src/core/include/units/quantity_cast.h index e4f8cb62..a2664339 100644 --- a/src/core/include/units/quantity_cast.h +++ b/src/core/include/units/quantity_cast.h @@ -27,6 +27,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,25 +50,31 @@ class quantity_point_kind; namespace detail { template -inline constexpr ratio quantity_ratio = std::enable_if_t>{}; +inline constexpr Magnitude auto quantity_magnitude = std::enable_if_t, magnitude<>>{}; template -inline constexpr ratio quantity_ratio> = [] { +inline constexpr Magnitude auto quantity_magnitude> = [] { if constexpr (BaseDimension) { - return U::ratio; + return U::mag; } else { - return D::base_units_ratio * U::ratio / D::coherent_unit::ratio; + return D::base_units_ratio * U::mag / D::coherent_unit::mag; } }(); +template +inline constexpr ratio quantity_ratio = std::enable_if_t>{}; + +template +inline constexpr ratio quantity_ratio> = as_ratio(quantity_magnitude>); + template -inline constexpr ratio cast_ratio = [] { +inline constexpr Magnitude auto cast_magnitude = [] { using FromU = TYPENAME QFrom::unit; using ToU = TYPENAME QTo::unit; if constexpr (same_unit_reference::value) { - return FromU::ratio / ToU::ratio; + return FromU::mag / ToU::mag; } else { - return quantity_ratio / quantity_ratio; + return quantity_magnitude / quantity_magnitude; } }(); @@ -112,24 +119,16 @@ template R using traits = detail::cast_traits; using ratio_type = TYPENAME traits::ratio_type; using rep_type = TYPENAME traits::rep_type; - constexpr auto c_ratio = detail::cast_ratio, To>; + constexpr Magnitude auto c_mag = detail::cast_magnitude, To>; if constexpr (treat_as_floating_point) { return To( - static_cast(static_cast(q.number()) * - (static_cast(c_ratio.num) * detail::fpow10(c_ratio.exp) / - static_cast(c_ratio.den)))); + static_cast(static_cast(q.number()) * (get_value(numerator(c_mag)) / + get_value(denominator(c_mag))))); } else { - if constexpr (c_ratio.exp > 0) { - return To(static_cast( - static_cast(q.number()) * - (static_cast(c_ratio.num) * static_cast(detail::ipow10(c_ratio.exp))) / - static_cast(c_ratio.den))); - } else { - return To(static_cast( - static_cast(q.number()) * static_cast(c_ratio.num) / - (static_cast(c_ratio.den) * static_cast(detail::ipow10(-c_ratio.exp))))); - } + return To( + static_cast(static_cast(q.number()) * get_value(numerator(c_mag)) / + get_value(denominator(c_mag)))); } } @@ -149,7 +148,7 @@ template requires equivalent [[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - return quantity_cast, Rep>>(q); + return quantity_cast, Rep>>(q); } /** diff --git a/src/core/include/units/reference.h b/src/core/include/units/reference.h index cca74b79..200cc2fb 100644 --- a/src/core/include/units/reference.h +++ b/src/core/include/units/reference.h @@ -37,13 +37,13 @@ namespace detail { template using reference_multiply_impl = - reference::ratio) * (U2::ratio / dimension_unit::ratio) * - dimension_unit::ratio>>; + reference::mag) * (U2::mag / dimension_unit::mag) * + dimension_unit::mag>>; template using reference_divide_impl = - reference::ratio) / (U2::ratio / dimension_unit::ratio) * - dimension_unit::ratio>>; + reference::mag) / (U2::mag / dimension_unit::mag) * + dimension_unit::mag>>; } // namespace detail diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index 81cec37b..62a37d47 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -28,6 +28,7 @@ // IWYU pragma: begin_exports #include #include +#include #include #include #include @@ -47,20 +48,18 @@ namespace units { * (i.e. all length units are expressed in terms of meter, all mass units are expressed in * terms of gram, ...) * - * @tparam R a ratio of a reference unit + * @tparam M a Magnitude representing the (relative) size of this unit * @tparam U a unit to use as a reference for this dimension */ -template - requires UnitRatio -struct scaled_unit : downcast_base> { - static constexpr ::units::ratio ratio = R; +template +struct scaled_unit : downcast_base> { + static constexpr ::units::ratio ratio = as_ratio(M); + static constexpr Magnitude auto mag = M; using reference = U; }; -template -// template // TODO: GCC crash!!! - requires UnitRatio -using downcast_unit = downcast::reference>>; +template +using downcast_unit = downcast::reference>>; template struct same_unit_reference : is_same {}; @@ -74,7 +73,7 @@ struct same_unit_reference : is_same -struct unit : downcast_dispatch> { +struct unit : downcast_dispatch(), Child>> { static constexpr bool is_named = false; using prefix_family = no_prefix; }; @@ -92,7 +91,7 @@ struct unit : downcast_dispatch> { * @tparam PF no_prefix or a type of prefix family */ template -struct named_unit : downcast_dispatch> { +struct named_unit : downcast_dispatch(), Child>> { static constexpr bool is_named = true; static constexpr auto symbol = Symbol; using prefix_family = PF; @@ -109,12 +108,11 @@ struct named_unit : downcast_dispatch> { * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) * @tparam Symbol a short text representation of the unit * @tparam PF no_prefix or a type of prefix family - * @tparam R a scale to apply to U + * @tparam M the Magnitude by which to scale U * @tparam U a reference unit to scale */ -template - requires UnitRatio -struct named_scaled_unit : downcast_dispatch> { +template +struct named_scaled_unit : downcast_dispatch> { static constexpr bool is_named = true; static constexpr auto symbol = Symbol; using prefix_family = PF; @@ -133,7 +131,7 @@ struct named_scaled_unit : downcast_dispatch requires U::is_named && std::same_as -struct prefixed_unit : downcast_dispatch> { +struct prefixed_unit : downcast_dispatch> { static constexpr bool is_named = true; static constexpr auto symbol = P::symbol + U::symbol; using prefix_family = no_prefix; diff --git a/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h b/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h index c8ea04f7..3e107d20 100644 --- a/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h +++ b/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h @@ -53,7 +53,7 @@ struct tebibit : prefixed_unit {}; struct pebibit : prefixed_unit {}; struct exbibit : prefixed_unit {}; -struct byte : named_scaled_unit {}; +struct byte : named_scaled_unit(), bit> {}; struct kilobyte : prefixed_unit {}; struct megabyte : prefixed_unit {}; struct gigabyte : prefixed_unit {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/force.h b/src/systems/si-fps/include/units/isq/si/fps/force.h index 8958ca44..330ad453 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/force.h +++ b/src/systems/si-fps/include/units/isq/si/fps/force.h @@ -40,7 +40,8 @@ namespace units::isq::si::fps { struct poundal : named_unit {}; // https://en.wikipedia.org/wiki/Pound_(force) -struct pound_force : named_scaled_unit {}; +struct pound_force : + named_scaled_unit(), poundal> {}; struct kilopound_force : prefixed_unit {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/length.h b/src/systems/si-fps/include/units/isq/si/fps/length.h index c037afe1..12b83ae5 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/length.h +++ b/src/systems/si-fps/include/units/isq/si/fps/length.h @@ -35,24 +35,24 @@ namespace units::isq::si::fps { // https://en.wikipedia.org/wiki/Foot_(unit) -struct foot : named_scaled_unit {}; +struct foot : named_scaled_unit(), si::metre> {}; -struct inch : named_scaled_unit {}; +struct inch : named_scaled_unit(), foot> {}; // thousandth of an inch -struct thousandth : named_scaled_unit {}; +struct thousandth : named_scaled_unit(), inch> {}; struct thou : alias_unit {}; struct mil : alias_unit {}; -struct yard : named_scaled_unit {}; +struct yard : named_scaled_unit(), foot> {}; -struct fathom : named_scaled_unit {}; +struct fathom : named_scaled_unit(), foot> {}; struct kiloyard : prefixed_unit {}; -struct mile : named_scaled_unit {}; +struct mile : named_scaled_unit(), foot> {}; -struct nautical_mile : named_scaled_unit {}; +struct nautical_mile : named_scaled_unit(), yard> {}; struct dim_length : isq::dim_length {}; diff --git a/src/systems/si-fps/include/units/isq/si/fps/mass.h b/src/systems/si-fps/include/units/isq/si/fps/mass.h index 559593d0..bc669e7f 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/mass.h +++ b/src/systems/si-fps/include/units/isq/si/fps/mass.h @@ -35,28 +35,29 @@ namespace units::isq::si::fps { // https://en.wikipedia.org/wiki/Pound_(mass) -struct pound : named_scaled_unit {}; +struct pound : + named_scaled_unit(), si::kilogram> {}; struct dim_mass : isq::dim_mass {}; template U, Representation Rep = double> using mass = quantity; -struct grain : named_scaled_unit {}; +struct grain : named_scaled_unit(), pound> {}; -struct dram : named_scaled_unit {}; +struct dram : named_scaled_unit(), pound> {}; -struct ounce : named_scaled_unit {}; +struct ounce : named_scaled_unit(), pound> {}; -struct stone : named_scaled_unit {}; +struct stone : named_scaled_unit(), pound> {}; -struct quarter : named_scaled_unit {}; +struct quarter : named_scaled_unit(), pound> {}; -struct hundredweight : named_scaled_unit {}; +struct hundredweight : named_scaled_unit(), pound> {}; -struct short_ton : named_scaled_unit {}; +struct short_ton : named_scaled_unit(), pound> {}; -struct long_ton : named_scaled_unit {}; +struct long_ton : named_scaled_unit(), pound> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-fps/include/units/isq/si/fps/power.h b/src/systems/si-fps/include/units/isq/si/fps/power.h index d48d1f31..ac589004 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/power.h +++ b/src/systems/si-fps/include/units/isq/si/fps/power.h @@ -41,7 +41,8 @@ struct dim_power : isq::dim_power {}; -struct horse_power : named_scaled_unit {}; +struct horse_power : + named_scaled_unit(), foot_pound_force_per_second> {}; template U, Representation Rep = double> using power = quantity; diff --git a/src/systems/si-fps/include/units/isq/si/fps/pressure.h b/src/systems/si-fps/include/units/isq/si/fps/pressure.h index 2c87269f..93c48eaf 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/pressure.h +++ b/src/systems/si-fps/include/units/isq/si/fps/pressure.h @@ -44,11 +44,12 @@ template U, Representation Rep = double> using pressure = quantity; struct pound_force_per_foot_sq : - named_scaled_unit(), poundal_per_foot_sq> {}; struct pound_force_per_inch_sq : - named_scaled_unit {}; + named_scaled_unit(), + pound_force_per_foot_sq> {}; struct kilopound_force_per_inch_sq : prefixed_unit {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/area.h b/src/systems/si-hep/include/units/isq/si/hep/area.h index 9718fb2d..e1e7a297 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/area.h +++ b/src/systems/si-hep/include/units/isq/si/hep/area.h @@ -37,7 +37,7 @@ namespace units::isq::si::hep { // effective cross-sectional area according to EU council directive 80/181/EEC // https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:01980L0181-20090527#page=10 // https://www.fedlex.admin.ch/eli/cc/1994/3109_3109_3109/de -struct barn : named_scaled_unit {}; +struct barn : named_scaled_unit(), square_metre> {}; struct yocto_barn : prefixed_unit {}; struct zepto_barn : prefixed_unit {}; struct atto_barn : prefixed_unit {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/mass.h b/src/systems/si-hep/include/units/isq/si/hep/mass.h index 2f617544..cdffd952 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/mass.h +++ b/src/systems/si-hep/include/units/isq/si/hep/mass.h @@ -32,11 +32,15 @@ #include #include +// Necessary to factor `1'672'621'923'695`, which appears in the proton mass. +template<> +inline constexpr std::optional units::known_first_factor<334'524'384'739> = 334'524'384'739; + namespace units::isq::si::hep { struct eV_per_c2 : named_scaled_unit {}; + as_magnitude(), kilogram> {}; struct feV_per_c2 : prefixed_unit {}; struct peV_per_c2 : prefixed_unit {}; struct neV_per_c2 : prefixed_unit {}; @@ -52,11 +56,14 @@ struct PeV_per_c2 : prefixed_unit {}; struct EeV_per_c2 : prefixed_unit {}; struct YeV_per_c2 : prefixed_unit {}; struct electron_mass : - named_scaled_unit {}; + named_scaled_unit(), + kilogram> {}; struct proton_mass : - named_scaled_unit {}; + named_scaled_unit(), + kilogram> {}; struct neutron_mass : - named_scaled_unit {}; + named_scaled_unit(), + kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/src/systems/si-hep/include/units/isq/si/hep/momentum.h b/src/systems/si-hep/include/units/isq/si/hep/momentum.h index 285f9d21..9cabfb15 100644 --- a/src/systems/si-hep/include/units/isq/si/hep/momentum.h +++ b/src/systems/si-hep/include/units/isq/si/hep/momentum.h @@ -36,7 +36,7 @@ namespace units::isq::si::hep { struct eV_per_c : - named_scaled_unit(), ::units::isq::si::kilogram_metre_per_second> {}; struct feV_per_c : prefixed_unit {}; struct peV_per_c : prefixed_unit {}; diff --git a/src/systems/si-iau/include/units/isq/si/iau/length.h b/src/systems/si-iau/include/units/isq/si/iau/length.h index ce0d1059..22350735 100644 --- a/src/systems/si-iau/include/units/isq/si/iau/length.h +++ b/src/systems/si-iau/include/units/isq/si/iau/length.h @@ -36,13 +36,13 @@ namespace units::isq::si::iau { // https://en.wikipedia.org/wiki/Light-year -struct light_year : named_scaled_unit {}; +struct light_year : named_scaled_unit(), si::metre> {}; // https://en.wikipedia.org/wiki/Parsec -struct parsec : named_scaled_unit {}; +struct parsec : named_scaled_unit(), si::metre> {}; // https://en.wikipedia.org/wiki/Angstrom -struct angstrom : named_scaled_unit {}; +struct angstrom : named_scaled_unit(), si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-imperial/include/units/isq/si/imperial/length.h b/src/systems/si-imperial/include/units/isq/si/imperial/length.h index eb5978c3..4136595a 100644 --- a/src/systems/si-imperial/include/units/isq/si/imperial/length.h +++ b/src/systems/si-imperial/include/units/isq/si/imperial/length.h @@ -35,10 +35,10 @@ namespace units::isq::si::imperial { // https://en.wikipedia.org/wiki/Chain_(unit) -struct chain : named_scaled_unit {}; +struct chain : named_scaled_unit(), si::international::yard> {}; // https://en.wikipedia.org/wiki/Rod_(unit) -struct rod : named_scaled_unit {}; +struct rod : named_scaled_unit(), chain> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-international/include/units/isq/si/international/length.h b/src/systems/si-international/include/units/isq/si/international/length.h index 38b7eac3..7ea729b7 100644 --- a/src/systems/si-international/include/units/isq/si/international/length.h +++ b/src/systems/si-international/include/units/isq/si/international/length.h @@ -37,30 +37,30 @@ namespace units::isq::si::international { // si::international yard // https://en.wikipedia.org/wiki/International_yard_and_pound -struct yard : named_scaled_unit {}; +struct yard : named_scaled_unit(), si::metre> {}; // si::international foot // https://en.wikipedia.org/wiki/Foot_(unit)#International_foot -struct foot : named_scaled_unit {}; +struct foot : named_scaled_unit(), yard> {}; // https://en.wikipedia.org/wiki/Fathom#International_fathom -struct fathom : named_scaled_unit {}; +struct fathom : named_scaled_unit(), yard> {}; // si::international inch // https://en.wikipedia.org/wiki/Inch#Equivalences -struct inch : named_scaled_unit {}; +struct inch : named_scaled_unit(), yard> {}; // intrnational mile // https://en.wikipedia.org/wiki/Mile#International_mile -struct mile : named_scaled_unit {}; +struct mile : named_scaled_unit(), si::kilometre> {}; // si::international nautical mile // https://en.wikipedia.org/wiki/Nautical_mile -struct nautical_mile : named_scaled_unit {}; +struct nautical_mile : named_scaled_unit(), si::metre> {}; // thou // https://en.wikipedia.org/wiki/Thousandth_of_an_inch -struct thou : named_scaled_unit {}; +struct thou : named_scaled_unit(), inch> {}; // mil - different name for thou // https://en.wikipedia.org/wiki/Thousandth_of_an_inch diff --git a/src/systems/si-typographic/include/units/isq/si/typographic/length.h b/src/systems/si-typographic/include/units/isq/si/typographic/length.h index cb3c691e..e8b4b5a8 100644 --- a/src/systems/si-typographic/include/units/isq/si/typographic/length.h +++ b/src/systems/si-typographic/include/units/isq/si/typographic/length.h @@ -37,10 +37,14 @@ namespace units::isq::si::typographic { // TODO Conflicts with (https://en.wikipedia.org/wiki/Pica_(typography)), verify correctness of below conversion factors // and provide hyperlinks to definitions -struct pica_comp : named_scaled_unit {}; -struct pica_prn : named_scaled_unit {}; -struct point_comp : named_scaled_unit {}; -struct point_prn : named_scaled_unit {}; +struct pica_comp : + named_scaled_unit(), si::metre> {}; +struct pica_prn : + named_scaled_unit(), si::metre> {}; +struct point_comp : + named_scaled_unit(), si::metre> {}; +struct point_prn : + named_scaled_unit(), si::metre> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si-uscs/include/units/isq/si/uscs/length.h b/src/systems/si-uscs/include/units/isq/si/uscs/length.h index b1c06b5f..83281090 100644 --- a/src/systems/si-uscs/include/units/isq/si/uscs/length.h +++ b/src/systems/si-uscs/include/units/isq/si/uscs/length.h @@ -36,14 +36,14 @@ namespace units::isq::si::uscs { // https://en.wikipedia.org/wiki/Foot_(unit)#US_survey_foot // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct foot : named_scaled_unit {}; +struct foot : named_scaled_unit(), si::metre> {}; // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct fathom : named_scaled_unit {}; +struct fathom : named_scaled_unit(), foot> {}; // https://en.wikipedia.org/wiki/Mile#U.S._survey_mile // https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6 -struct mile : named_scaled_unit {}; +struct mile : named_scaled_unit(), foot> {}; #ifndef UNITS_NO_LITERALS diff --git a/src/systems/si/include/units/isq/si/catalytic_activity.h b/src/systems/si/include/units/isq/si/catalytic_activity.h index 9c348d88..ad52a9d2 100644 --- a/src/systems/si/include/units/isq/si/catalytic_activity.h +++ b/src/systems/si/include/units/isq/si/catalytic_activity.h @@ -58,7 +58,7 @@ struct exakatal : prefixed_unit {}; struct zettakatal : prefixed_unit {}; struct yottakatal : prefixed_unit {}; -struct enzyme_unit : named_scaled_unit {}; +struct enzyme_unit : named_scaled_unit(), katal> {}; struct dim_catalytic_activity : isq::dim_catalytic_activity {}; diff --git a/src/systems/si/include/units/isq/si/energy.h b/src/systems/si/include/units/isq/si/energy.h index 2ca2fc9b..6efa1478 100644 --- a/src/systems/si/include/units/isq/si/energy.h +++ b/src/systems/si/include/units/isq/si/energy.h @@ -55,7 +55,8 @@ struct yottajoule : prefixed_unit {}; // N.B. electron charge (and eV) is an exact constant: // https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf#page=147 -struct electronvolt : named_scaled_unit {}; +struct electronvolt : + named_scaled_unit(), joule> {}; struct gigaelectronvolt : prefixed_unit {}; struct dim_energy : isq::dim_energy {}; diff --git a/src/systems/si/include/units/isq/si/length.h b/src/systems/si/include/units/isq/si/length.h index eee2c9d2..582a9ae3 100644 --- a/src/systems/si/include/units/isq/si/length.h +++ b/src/systems/si/include/units/isq/si/length.h @@ -56,7 +56,8 @@ struct exametre : prefixed_unit {}; struct zettametre : prefixed_unit {}; struct yottametre : prefixed_unit {}; -struct astronomical_unit : named_scaled_unit {}; +struct astronomical_unit : + named_scaled_unit(), metre> {}; struct dim_length : isq::dim_length {}; diff --git a/src/systems/si/include/units/isq/si/magnetic_induction.h b/src/systems/si/include/units/isq/si/magnetic_induction.h index 353a3af0..bdb33ef7 100644 --- a/src/systems/si/include/units/isq/si/magnetic_induction.h +++ b/src/systems/si/include/units/isq/si/magnetic_induction.h @@ -56,7 +56,7 @@ struct exatesla : prefixed_unit {}; struct zettatesla : prefixed_unit {}; struct yottatesla : prefixed_unit {}; -struct gauss : named_scaled_unit {}; +struct gauss : named_scaled_unit(), tesla> {}; struct dim_magnetic_induction : isq::dim_magnetic_induction {}; diff --git a/src/systems/si/include/units/isq/si/mass.h b/src/systems/si/include/units/isq/si/mass.h index 620381b3..d9d7fdf7 100644 --- a/src/systems/si/include/units/isq/si/mass.h +++ b/src/systems/si/include/units/isq/si/mass.h @@ -79,7 +79,8 @@ struct zettatonne : prefixed_unit {}; struct yottatonne : prefixed_unit {}; struct dalton : - named_scaled_unit {}; + named_scaled_unit(), + kilogram> {}; struct dim_mass : isq::dim_mass {}; diff --git a/src/systems/si/include/units/isq/si/time.h b/src/systems/si/include/units/isq/si/time.h index 7c1d4d5c..34d7c025 100644 --- a/src/systems/si/include/units/isq/si/time.h +++ b/src/systems/si/include/units/isq/si/time.h @@ -43,9 +43,9 @@ struct picosecond : prefixed_unit {}; struct nanosecond : prefixed_unit {}; struct microsecond : prefixed_unit {}; struct millisecond : prefixed_unit {}; -struct minute : named_scaled_unit {}; -struct hour : named_scaled_unit {}; -struct day : named_scaled_unit {}; +struct minute : named_scaled_unit(), second> {}; +struct hour : named_scaled_unit(), minute> {}; +struct day : named_scaled_unit(), hour> {}; struct dim_time : isq::dim_time {}; diff --git a/test/unit_test/runtime/fmt_test.cpp b/test/unit_test/runtime/fmt_test.cpp index abc595e6..3ec5211e 100644 --- a/test/unit_test/runtime/fmt_test.cpp +++ b/test/unit_test/runtime/fmt_test.cpp @@ -84,7 +84,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") { SECTION("in terms of base units") { - const length> q(123); + const length(as_magnitude<10>()), metre>> q(123); os << q; SECTION("iostream") { CHECK(os.str() == "123 Mm"); } @@ -96,7 +96,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("in terms of derived units") { - const energy> q(60); + const energy(as_magnitude<10>()), joule>> q(60); os << q; SECTION("iostream") { CHECK(os.str() == "60 cJ"); } @@ -257,7 +257,8 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") const auto q = 60_q_kJ / 2_q_min; os << q; - SECTION("iostream") { CHECK(os.str() == "30 [1/6 × 10²] W"); } + // TODO(chogg): Reinstate after format/Magnitude design. + // SECTION("iostream") { CHECK(os.str() == "30 [1/6 × 10²] W"); } SECTION("fmt with default format {} on a quantity") { CHECK(STD_FMT::format("{}", q) == os.str()); } @@ -390,7 +391,8 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") const auto q = 60_q_min / 2_q_km; os << q; - SECTION("iostream") { CHECK(os.str() == "30 [6 × 10⁻²] 1/m ⋅ s"); } + // TODO(chogg): Reinstate after format/Magnitude design. + // SECTION("iostream") { CHECK(os.str() == "30 [6 × 10⁻²] 1/m ⋅ s"); } SECTION("fmt with default format {} on a quantity") { CHECK(STD_FMT::format("{}", q) == os.str()); } diff --git a/test/unit_test/runtime/fmt_units_test.cpp b/test/unit_test/runtime/fmt_units_test.cpp index c94c3734..a3068eac 100644 --- a/test/unit_test/runtime/fmt_units_test.cpp +++ b/test/unit_test/runtime/fmt_units_test.cpp @@ -30,6 +30,7 @@ #include #include #include +#include using namespace units::isq::si; using namespace units::isq::si::references; @@ -315,16 +316,18 @@ TEST_CASE("std::format on synthesized unit symbols", "[text][fmt]") SECTION("incoherent units with powers") { - CHECK(STD_FMT::format("{}", 1_q_mi * 1_q_mi * 1_q_mi) == "1 [15900351812136/3814697265625 × 10⁹] m³"); - CHECK(STD_FMT::format("{}", 1_q_au * 1_q_au) == "1 [2237952291797391849 × 10⁴] m²"); - - CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_mi * 1_q_mi * 1_q_mi) == "1 [15900351812136/3814697265625 x 10^9] m^3"); - CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_au * 1_q_au) == "1 [2237952291797391849 x 10^4] m^2"); + // TODO(chogg): Reinstate after format/Magnitude redesign. + // CHECK(STD_FMT::format("{}", 1_q_mi * 1_q_mi * 1_q_mi) == "1 [15900351812136/3814697265625 × 10⁹] m³"); + // CHECK(STD_FMT::format("{}", 1_q_au * 1_q_au) == "1 [2237952291797391849 × 10⁴] m²"); + // + // CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_mi * 1_q_mi * 1_q_mi) == "1 [15900351812136/3814697265625 x 10^9] m^3"); + // CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_au * 1_q_au) == "1 [2237952291797391849 x 10^4] m^2"); } SECTION("unknown scaled unit with reference different than the dimension's coherent unit") { - CHECK(STD_FMT::format("{}", mass>(1)) == "1 [2/3 × 10⁻³] kg"); - CHECK(STD_FMT::format("{:%Q %Aq}", mass>(1)) == "1 [2/3 x 10^-3] kg"); + constexpr auto mag = units::as_magnitude(); + CHECK(STD_FMT::format("{}", mass>(1)) == "1 [2/3 × 10⁻³] kg"); + CHECK(STD_FMT::format("{:%Q %Aq}", mass>(1)) == "1 [2/3 x 10^-3] kg"); } } diff --git a/test/unit_test/static/concepts_test.cpp b/test/unit_test/static/concepts_test.cpp index d1c1e2bf..a97a1e13 100644 --- a/test/unit_test/static/concepts_test.cpp +++ b/test/unit_test/static/concepts_test.cpp @@ -53,15 +53,6 @@ static_assert(Prefix); static_assert(!Prefix); static_assert(!Prefix); -// UnitRatio - -static_assert(UnitRatio); -static_assert(!UnitRatio); -// static_assert(UnitRatio); // static_assert in ratio -static_assert(UnitRatio); -static_assert(!UnitRatio); -static_assert(!UnitRatio); - // BaseDimension static_assert(BaseDimension); diff --git a/test/unit_test/static/quantity_kind_test.cpp b/test/unit_test/static/quantity_kind_test.cpp index adbfeb8d..f7d4f642 100644 --- a/test/unit_test/static/quantity_kind_test.cpp +++ b/test/unit_test/static/quantity_kind_test.cpp @@ -456,9 +456,9 @@ concept invalid_compound_assignments = requires !requires { w *= m; }; requires !requires { w /= m; }; requires !requires { w %= m; }; - requires !requires { w *= quantity_kind, scaled_unit, int>{1}; }; - requires !requires { w /= quantity_kind, scaled_unit, int>{1}; }; - requires !requires { w %= quantity_kind, scaled_unit, int>{1}; }; + requires !requires { w *= quantity_kind, scaled_unit(), one>, int>{1}; }; + requires !requires { w /= quantity_kind, scaled_unit(), one>, int>{1}; }; + requires !requires { w %= quantity_kind, scaled_unit(), one>, int>{1}; }; requires !requires { w %= 1.0; }; requires !requires { w %= quantity(1.0); }; requires !requires { w %= 1.0 * (w / w); }; diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 0f810ccf..73985198 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -496,7 +496,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), - frequency, std::int64_t>>); + frequency(), hertz>, std::int64_t>>); static_assert(is_same_v); static_assert(is_same_v); @@ -527,7 +527,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1._q_s), - frequency, long double>>); + frequency(), hertz>, long double>>); static_assert(compare>); static_assert(compare>); static_assert(compare(1)), length>); @@ -549,7 +549,7 @@ static_assert(compare> static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), - frequency, long double>>); + frequency(), hertz>, long double>>); // different units static_assert(is_same_v>); @@ -577,22 +577,25 @@ static_assert(is_same_v>); -static_assert(compare, std::int64_t>>); +static_assert( + compare(), metre>, std::int64_t>>); static_assert( compare, exponent>, - scaled_unit, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); static_assert(compare>); -static_assert(compare, std::int64_t>>); -static_assert(compare>); static_assert( - compare>, - scaled_unit, std::int64_t>>); -static_assert(compare, std::int64_t>>); + compare(), hertz>, std::int64_t>>); +static_assert(compare>); +static_assert(compare>, + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); +static_assert(compare(), one>, std::int64_t>>); static_assert(compare>); -static_assert(compare, std::int64_t>>); +static_assert( + compare(), metre_per_second>, std::int64_t>>); static_assert( compare, exponent>, - scaled_unit, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); static_assert((1_q_m + 1_q_m).number() == 2); static_assert((1_q_m + 1_q_km).number() == 1001); @@ -882,8 +885,9 @@ static_assert(!is_same_v(2_q_dm3)), volume, units::exponent>, - scaled_unit, std::int64_t>>); -static_assert(is_same_v, std::int64_t>>); + scaled_unit(), unknown_coherent_unit>, std::int64_t>>); +static_assert( + is_same_v(), metre>, std::int64_t>>); #else @@ -913,7 +917,8 @@ static_assert(same(quotient_remainder_theorem(3'000 * m, 400), 3'000 * m)); static_assert(same(quotient_remainder_theorem(3'000 * m, quantity(400)), 3'000 * m)); static_assert(same(quotient_remainder_theorem(3 * km, quantity(400)), 3 * km)); static_assert(same(quotient_remainder_theorem(3 * km, quantity(2)), 3 * km)); -static_assert(same(quotient_remainder_theorem(3 * km, dimensionless, int>(400)), - 3 * km)); +static_assert( + same(quotient_remainder_theorem(3 * km, dimensionless(), one>, int>(400)), + 3 * km)); } // namespace diff --git a/test/unit_test/static/si_test.cpp b/test/unit_test/static/si_test.cpp index a69c1f1b..9070110d 100644 --- a/test/unit_test/static/si_test.cpp +++ b/test/unit_test/static/si_test.cpp @@ -43,7 +43,7 @@ static_assert(1_q_au == 149'597'870'700_q_m); static_assert(1_q_km + 1_q_m == 1001_q_m); static_assert(10_q_km / 5_q_km == 2); static_assert(10_q_km / 5_q_km < 3); -static_assert(100_q_mm / 5_q_cm == dimensionless>(20)); +static_assert(100_q_mm / 5_q_cm == dimensionless(), one>>(20)); static_assert(100_q_mm / 5_q_cm == dimensionless(2)); static_assert(10_q_km / 2 == 5_q_km); @@ -107,7 +107,7 @@ static_assert(1000 / 1_q_s == 1_q_kHz); static_assert(1 / 1_q_ms == 1_q_kHz); static_assert(3.2_q_GHz == 3'200'000'000_q_Hz); static_assert((10_q_Hz * 1_q_min).number() == 10); -static_assert(10_q_Hz * 1_q_min == dimensionless>(10)); +static_assert(10_q_Hz * 1_q_min == dimensionless(), one>>(10)); static_assert(10_q_Hz * 1_q_min == dimensionless(600)); static_assert(2 / 1_q_Hz == 2_q_s); diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index 4856b09a..a185a150 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -36,12 +36,12 @@ using namespace units::isq; struct metre : named_unit {}; struct centimetre : prefixed_unit {}; struct kilometre : prefixed_unit {}; -struct yard : named_scaled_unit {}; -struct foot : named_scaled_unit {}; +struct yard : named_scaled_unit(), metre> {}; +struct foot : named_scaled_unit(), yard> {}; struct dim_length : base_dimension<"length", metre> {}; struct second : named_unit {}; -struct hour : named_scaled_unit {}; +struct hour : named_scaled_unit(), second> {}; struct dim_time : base_dimension<"time", second> {}; struct kelvin : named_unit {}; @@ -59,17 +59,21 @@ struct kilometre_per_hour : derived_unit); static_assert(equivalent); -static_assert(compare>, metre>); -static_assert(compare>, centimetre>); -static_assert(compare>, yard>); -static_assert(compare>, foot>); -static_assert(compare>, kilometre_per_hour>); +static_assert(compare(), metre>>, metre>); +static_assert(compare(), metre>>, centimetre>); +static_assert( + compare(), metre>>, + yard>); +static_assert(compare(), metre>>, foot>); +static_assert(compare>, kilometre_per_hour>); -#if !UNITS_COMP_MSVC -static_assert([]() { - return !requires { typename scaled_unit; }; -}.template operator()()); // negative unit ratio -#endif +// We should delete this test case, because we are switching from ratio to Magnitude, and a negative Magnitude cannot +// even be formed. +// #if !UNITS_COMP_MSVC +// static_assert([]() { +// return !requires { typename scaled_unit; }; +// }.template operator()()>()); // negative unit ratio +// #endif static_assert(centimetre::symbol == "cm"); static_assert(kilometre::symbol == "km");