From 85f56d3faa6bdbc0babefbd34f8d88df792cf8c9 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Mon, 29 Jul 2024 21:17:06 -0400 Subject: [PATCH] Permit integer-dividing quantity-equivalent units This means we need to know the unit inside of `warn_if_integer_division()`, which seems OK. For the raw number cases, we synthesize a unitless unit. One weird thing is that sometimes the template parameters for `warn_if_integer_division()` are for the numerator, and sometimes for the denominator. But it still gives the correct answer in all cases. If both are `Quantity` types, then it doesn't matter which is which, because "both integers and quantity-inequivalent units" is symmetric. And if one is a raw number, then `warn_if_integer_division()` is _not_ symmetric, but that's fine because we simply don't _call it_ from the `Q / N` variant (which is always fine); we only call it from the `N / Q` variant (which might not be fine). Fixes #249. --- au/code/au/quantity.hh | 10 ++++++---- au/code/au/quantity_test.cc | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/au/code/au/quantity.hh b/au/code/au/quantity.hh index b567d43a..037f2164 100644 --- a/au/code/au/quantity.hh +++ b/au/code/au/quantity.hh @@ -310,7 +310,7 @@ class Quantity { } template ::value>> friend constexpr auto operator/(T s, Quantity a) { - warn_if_integer_division(); + warn_if_integer_division, T>(); return make_quantity(unit))>(s / a.value_); } @@ -324,7 +324,7 @@ class Quantity { // Division for dimensioned quantities. template constexpr auto operator/(Quantity q) const { - warn_if_integer_division(); + warn_if_integer_division(); return make_quantity_unless_unitless>(value_ / q.in(OtherUnit{})); } @@ -387,11 +387,13 @@ class Quantity { } private: - template + template static constexpr void warn_if_integer_division() { constexpr bool uses_integer_division = (std::is_integral::value && std::is_integral::value); - static_assert(!uses_integer_division, + constexpr bool are_units_quantity_equivalent = + AreUnitsQuantityEquivalent::value; + static_assert(are_units_quantity_equivalent || !uses_integer_division, "Integer division forbidden: use integer_quotient() if you really want it"); } diff --git a/au/code/au/quantity_test.cc b/au/code/au/quantity_test.cc index ed4c4c85..939b9ebc 100644 --- a/au/code/au/quantity_test.cc +++ b/au/code/au/quantity_test.cc @@ -852,6 +852,11 @@ TEST(integer_quotient, EnablesIntegerDivision) { EXPECT_THAT(freq, SameTypeAndValue(inverse(minutes)(3))); } +TEST(Quantity, CanIntegerDivideQuantitiesOfQuantityEquivalentUnits) { + constexpr auto ratio = meters(60) / meters(25); + EXPECT_EQ(ratio, 2); +} + TEST(mod, ComputesRemainderForSameUnits) { constexpr auto remainder = inches(50) % inches(12); EXPECT_THAT(remainder, QuantityEquivalent(inches(2)));