Skip to content

Commit

Permalink
Permit integer-dividing quantity-equivalent units
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
chiphogg committed Jul 30, 2024
1 parent db50c45 commit 85f56d3
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 4 deletions.
10 changes: 6 additions & 4 deletions au/code/au/quantity.hh
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ class Quantity {
}
template <typename T, typename = std::enable_if_t<IsQuotientValidRep<T, RepT>::value>>
friend constexpr auto operator/(T s, Quantity a) {
warn_if_integer_division<T>();
warn_if_integer_division<UnitProductT<>, T>();
return make_quantity<decltype(pow<-1>(unit))>(s / a.value_);
}

Expand All @@ -324,7 +324,7 @@ class Quantity {
// Division for dimensioned quantities.
template <typename OtherUnit, typename OtherRep>
constexpr auto operator/(Quantity<OtherUnit, OtherRep> q) const {
warn_if_integer_division<OtherRep>();
warn_if_integer_division<OtherUnit, OtherRep>();
return make_quantity_unless_unitless<UnitQuotientT<Unit, OtherUnit>>(value_ /
q.in(OtherUnit{}));
}
Expand Down Expand Up @@ -387,11 +387,13 @@ class Quantity {
}

private:
template <typename OtherRep>
template <typename OtherUnit, typename OtherRep>
static constexpr void warn_if_integer_division() {
constexpr bool uses_integer_division =
(std::is_integral<Rep>::value && std::is_integral<OtherRep>::value);
static_assert(!uses_integer_division,
constexpr bool are_units_quantity_equivalent =
AreUnitsQuantityEquivalent<UnitT, OtherUnit>::value;
static_assert(are_units_quantity_equivalent || !uses_integer_division,
"Integer division forbidden: use integer_quotient() if you really want it");
}

Expand Down
5 changes: 5 additions & 0 deletions au/code/au/quantity_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down

0 comments on commit 85f56d3

Please sign in to comment.