aurora-opensource / au

A C++14-compatible physical units library with no dependencies and a single-file delivery option. Emphasis on safety, accessibility, performance, and developer experience.
Apache License 2.0
329 stars 21 forks source link

Improve error messages for bad maker calls #294

Closed chiphogg closed 2 months ago

chiphogg commented 2 months ago

This covers situations where somebody calls a QuantityMaker, or QuantityPointMaker, on a value that isn't a valid rep. (One of the most common use cases is when the value is already a core Au type, a Quantity or QuantityMaker, and the call is redundant.

The first approach is a blanket approach: we start enforcing the "valid rep" definition that we had previously added. This already makes the error messages a lot nicer and shorter.

We then go further for the most common use case of redundant maker calls. By adding templated overloads to each maker for Quantity and QuantityPoint, we can directly tell users what they did wrong. In order to implement these overloads, we needed an AlwaysFalse utliity, which we added along with unit tests.

Helps #288. We will follow up to close this out by updating the troubleshooting guide.

chiphogg commented 2 months ago

Here are the example changes to tests, for posterity.

Input code

TEST(Quantity, OfQuantityMakesNiceErrorMessage) {
    radians(radians);
    radians(radians(3.14));
    meters(meters_pt(15));
    meters_pt(meters_pt(51));
    meters_pt(meters(51));
}

Old error messages

In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:287:68: error: invalid operands to binary expression ('au::QuantityMaker<au::Radians>' and 'au::QuantityMaker<au::Radians>')
    friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() + std::declval<RepT>())>
                                              ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:489:33: note: in instantiation of template class 'au::Quantity<au::Radians, au::QuantityMaker<au::Radians>>' requested here
    constexpr Quantity<Unit, T> operator()(T value) const {
                                ^
au/code/au/au_test.cc:94:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Radians>::operator()<au::QuantityMaker<au::Radians>>' requested here
    radians(radians);
           ^
au/code/au/zero.hh:55:23: note: candidate function not viable: no known conversion from 'au::QuantityMaker<au::Radians>' to 'au::Zero' for 1st argument
inline constexpr Zero operator+(Zero, Zero) { return ZERO; }
                      ^
au/code/au/quantity.hh:623:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator+(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
               ^
au/code/au/quantity.hh:633:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator+(Quantity<U, R> q1, QLike q2) -> decltype(q1 + as_quantity(q2)) {
               ^
au/code/au/quantity.hh:667:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator+(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) + q2) {
               ^
au/code/au/quantity_point.hh:395:16: note: candidate template ignored: could not match 'QuantityPoint' against 'QuantityMaker'
constexpr auto operator+(QuantityPoint<UnitP, RepP> p, Quantity<UnitQ, RepQ> q) {
               ^
au/code/au/quantity_point.hh:400:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator+(Quantity<UnitQ, RepQ> q, QuantityPoint<UnitP, RepP> p) {
               ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:291:68: error: invalid operands to binary expression ('au::QuantityMaker<au::Radians>' and 'au::QuantityMaker<au::Radians>')
    friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() - std::declval<RepT>())>
                                              ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
au/code/au/zero.hh:56:23: note: candidate function not viable: no known conversion from 'au::QuantityMaker<au::Radians>' to 'au::Zero' for 1st argument
inline constexpr Zero operator-(Zero, Zero) { return ZERO; }
                      ^
au/code/au/quantity.hh:627:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator-(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
               ^
au/code/au/quantity.hh:637:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator-(Quantity<U, R> q1, QLike q2) -> decltype(q1 - as_quantity(q2)) {
               ^
au/code/au/quantity.hh:671:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityMaker'
constexpr auto operator-(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) - q2) {
               ^
au/code/au/quantity_point.hh:405:16: note: candidate template ignored: could not match 'QuantityPoint' against 'QuantityMaker'
constexpr auto operator-(QuantityPoint<UnitP, R1> p, Quantity<UnitQ, RepQ> q) {
               ^
au/code/au/quantity_point.hh:410:16: note: candidate template ignored: could not match 'QuantityPoint' against 'QuantityMaker'
constexpr auto operator-(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
               ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:287:68: error: invalid operands to binary expression ('au::QuantityPoint<au::Meters, int>' and 'au::QuantityPoint<au::Meters, int>')
    friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() + std::declval<RepT>())>
                                              ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:489:33: note: in instantiation of template class 'au::Quantity<au::Meters, au::QuantityPoint<au::Meters, int>>' requested here
    constexpr Quantity<Unit, T> operator()(T value) const {
                                ^
au/code/au/au_test.cc:96:11: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::QuantityPoint<au::Meters, int>>' requested here
    meters(meters_pt(15));
          ^
au/code/au/quantity_point.hh:250:27: note: candidate function not viable: no known conversion from 'au::QuantityPoint<au::Meters, int>' to 'au::QuantityPoint<au::Meters, int>::Diff' (aka 'Quantity<au::Meters, int>') for 1st argument
    constexpr friend auto operator+(Diff d, QuantityPoint p) { return QuantityPoint{d + p.x_}; }
                          ^
au/code/au/quantity_point.hh:251:27: note: candidate function not viable: no known conversion from 'au::QuantityPoint<au::Meters, int>' to 'au::QuantityPoint<au::Meters, int>::Diff' (aka 'Quantity<au::Meters, int>') for 2nd argument
    constexpr friend auto operator+(QuantityPoint p, Diff d) { return QuantityPoint{p.x_ + d}; }
                          ^
au/code/au/zero.hh:55:23: note: candidate function not viable: no known conversion from 'au::QuantityPoint<au::Meters, int>' to 'au::Zero' for 1st argument
inline constexpr Zero operator+(Zero, Zero) { return ZERO; }
                      ^
au/code/au/quantity.hh:623:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
               ^
au/code/au/quantity.hh:633:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(Quantity<U, R> q1, QLike q2) -> decltype(q1 + as_quantity(q2)) {
               ^
au/code/au/quantity.hh:667:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) + q2) {
               ^
au/code/au/quantity_point.hh:395:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(QuantityPoint<UnitP, RepP> p, Quantity<UnitQ, RepQ> q) {
               ^
au/code/au/quantity_point.hh:400:16: note: candidate template ignored: could not match 'Quantity' against 'QuantityPoint'
constexpr auto operator+(Quantity<UnitQ, RepQ> q, QuantityPoint<UnitP, RepP> p) {
               ^
au/code/au/quantity_point.hh:80:88: error: invalid operands to binary expression ('au::Quantity<au::Meters, au::QuantityPoint<au::Meters, int>>' and 'au::Zero')
            decltype(std::declval<typename QuantityPoint<OtherUnit, OtherRep>::Diff>() +
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
au/code/au/quantity_point.hh:91:24: note: in instantiation of function template specialization 'au::QuantityPoint<au::Meters, au::QuantityPoint<au::Meters, int>>::should_enable_implicit_construction_from<au::Meters, au::QuantityPoint<au::Meters, int>>' requested here
        QuantityPoint::should_enable_implicit_construction_from<OtherUnit, OtherRep>()>;
                       ^
au/code/au/quantity_point.hh:107:33: note: in instantiation of template type alias 'EnableIfImplicitOkIs' requested here
              typename Enable = EnableIfImplicitOkIs<true, OtherUnit, OtherRep>>
                                ^
au/code/au/quantity_point.hh:108:15: note: in instantiation of default argument for 'QuantityPoint<au::Meters, au::QuantityPoint<au::Meters, int>>' required here
    constexpr QuantityPoint(QuantityPoint<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity_point.hh:287:16: note: while substituting deduced template arguments into function template 'QuantityPoint' [with OtherUnit = au::Meters, OtherRep = au::QuantityPoint<au::Meters, int>, Enable = (no value)]
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
               ^
au/code/au/au_test.cc:97:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::QuantityPoint<au::Meters, int>>' requested here
    meters_pt(meters_pt(51));
             ^
au/code/au/zero.hh:55:23: note: candidate function not viable: no known conversion from 'au::Quantity<au::Meters, au::QuantityPoint<au::Meters, int>>' to 'au::Zero' for 1st argument
inline constexpr Zero operator+(Zero, Zero) { return ZERO; }
                      ^
au/code/au/quantity_point.hh:250:27: note: candidate function not viable: no known conversion from 'Quantity<[...], au::QuantityPoint<au::Meters, int>>' to 'Quantity<[...], au::QuantityPoint<au::Meters, int>::Rep>' for 1st argument
    constexpr friend auto operator+(Diff d, QuantityPoint p) { return QuantityPoint{d + p.x_}; }
                          ^
au/code/au/quantity_point.hh:251:27: note: candidate function not viable: no known conversion from 'au::Quantity<au::Meters, au::QuantityPoint<au::Meters, int>>' to 'au::QuantityPoint<au::Meters, int>' for 1st argument
    constexpr friend auto operator+(QuantityPoint p, Diff d) { return QuantityPoint{p.x_ + d}; }
                          ^
au/code/au/quantity.hh:623:16: note: candidate template ignored: could not match 'Quantity<U2, R2>' against 'au::Zero'
constexpr auto operator+(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
               ^
au/code/au/quantity.hh:633:16: note: candidate template ignored: substitution failure [with U = au::Meters, R = au::QuantityPoint<au::Meters, int>, QLike = au::Zero]: no matching function for call to 'as_quantity'
constexpr auto operator+(Quantity<U, R> q1, QLike q2) -> decltype(q1 + as_quantity(q2)) {
               ^                                                       ~~~~~~~~~~~
au/code/au/quantity.hh:667:16: note: candidate template ignored: could not match 'Quantity<U, R>' against 'au::Zero'
constexpr auto operator+(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) + q2) {
               ^
au/code/au/quantity_point.hh:395:16: note: candidate template ignored: could not match 'QuantityPoint' against 'Quantity'
constexpr auto operator+(QuantityPoint<UnitP, RepP> p, Quantity<UnitQ, RepQ> q) {
               ^
au/code/au/quantity_point.hh:400:16: note: candidate template ignored: could not match 'QuantityPoint<UnitP, RepP>' against 'au::Zero'
constexpr auto operator+(Quantity<UnitQ, RepQ> q, QuantityPoint<UnitP, RepP> p) {
               ^
au/code/au/quantity.hh:371:24: note: candidate function not viable: requires 0 arguments, but 2 were provided
    constexpr Quantity operator+() const { return {+value_}; }
                       ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:19:
In file included from au/code/au/apply_magnitude.hh:17:
In file included from au/code/au/apply_rational_magnitude_to_integral.hh:19:
In file included from au/code/au/magnitude.hh:21:
au/code/au/stdx/utility.hh:100:65: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
    constexpr bool operator()(T t, U u) { return t < 0 ? true : std::make_unsigned_t<T>(t) < u; }
                                                                ^
au/code/au/stdx/utility.hh:46:12: note: in instantiation of member function 'au::stdx::CmpLessImpl<int, au::Quantity<au::Meters, int>>::operator()' requested here
    return CmpLessImpl<T, U>{}(t, u);
           ^
au/code/au/stdx/utility.hh:64:13: note: in instantiation of function template specialization 'au::stdx::cmp_less<int, au::Quantity<au::Meters, int>>' requested here
    return !cmp_less(t, u);
            ^
au/code/au/stdx/utility.hh:70:12: note: in instantiation of function template specialization 'au::stdx::cmp_greater_equal<int, au::Quantity<au::Meters, int>>' requested here
    return cmp_greater_equal(t, std::numeric_limits<R>::min()) &&
           ^
au/code/au/conversion_policy.hh:47:37: note: in instantiation of function template specialization 'au::stdx::in_range<au::Quantity<au::Meters, int>, int>' requested here
          stdx::bool_constant<stdx::in_range<Rep>(OVERFLOW_THRESHOLD)>,
                                    ^
au/code/au/stdx/type_traits.hh:36:25: note: in instantiation of template class 'au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>' requested here
struct conjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:38:32: note: (skipping 10 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
struct conjunction<B, Bn...> : std::conditional_t<bool(B::value), conjunction<Bn...>, B> {};
                               ^
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:19:
In file included from au/code/au/apply_magnitude.hh:17:
In file included from au/code/au/apply_rational_magnitude_to_integral.hh:19:
In file included from au/code/au/magnitude.hh:21:
au/code/au/stdx/utility.hh:105:70: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
    constexpr bool operator()(T t, U u) { return u < 0 ? false : t < std::make_unsigned_t<U>(u); }
                                                                     ^
au/code/au/stdx/utility.hh:46:12: note: in instantiation of member function 'au::stdx::CmpLessImpl<au::Quantity<au::Meters, int>, int>::operator()' requested here
    return CmpLessImpl<T, U>{}(t, u);
           ^
au/code/au/stdx/utility.hh:52:12: note: in instantiation of function template specialization 'au::stdx::cmp_less<au::Quantity<au::Meters, int>, int>' requested here
    return cmp_less(u, t);
           ^
au/code/au/stdx/utility.hh:58:13: note: in instantiation of function template specialization 'au::stdx::cmp_greater<int, au::Quantity<au::Meters, int>>' requested here
    return !cmp_greater(t, u);
            ^
au/code/au/stdx/utility.hh:71:12: note: in instantiation of function template specialization 'au::stdx::cmp_less_equal<int, au::Quantity<au::Meters, int>>' requested here
           cmp_less_equal(t, std::numeric_limits<R>::max());
           ^
au/code/au/conversion_policy.hh:47:37: note: in instantiation of function template specialization 'au::stdx::in_range<au::Quantity<au::Meters, int>, int>' requested here
          stdx::bool_constant<stdx::in_range<Rep>(OVERFLOW_THRESHOLD)>,
                                    ^
au/code/au/stdx/type_traits.hh:36:25: note: (skipping 11 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
struct conjunction<B> : B {};
                        ^
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:19:
In file included from au/code/au/apply_magnitude.hh:17:
In file included from au/code/au/apply_rational_magnitude_to_integral.hh:19:
au/code/au/magnitude.hh:519:43: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
    return {MagRepresentationOutcome::OK, static_cast<T>(1)};
                                          ^
au/code/au/magnitude.hh:534:29: note: in instantiation of function template specialization 'au::detail::get_value_result<au::Quantity<au::Meters, int>>' requested here
    constexpr auto result = get_value_result<T>(m);
                            ^
au/code/au/conversion_policy.hh:34:50: note: in instantiation of function template specialization 'au::get_value<au::Quantity<au::Meters, int>>' requested here
        return std::numeric_limits<Rep>::max() / get_value<Rep>(m) >= value;
                                                 ^
au/code/au/conversion_policy.hh:48:31: note: in instantiation of function template specialization 'au::can_scale_without_overflow<au::Quantity<au::Meters, int>>' requested here
          stdx::bool_constant<can_scale_without_overflow<Rep>(ScaleFactor{}, OVERFLOW_THRESHOLD)>> {
                              ^
au/code/au/stdx/type_traits.hh:36:25: note: in instantiation of template class 'au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>' requested here
struct conjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct conjunction<B, Bn...> : std::conditional_t<bool(B::value), conjunction<Bn...>, B> {};
                               ^
au/code/au/stdx/type_traits.hh:38:32: note: (skipping 9 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:20:
au/code/au/conversion_policy.hh:34:16: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
        return std::numeric_limits<Rep>::max() / get_value<Rep>(m) >= value;
               ^
au/code/au/conversion_policy.hh:48:31: note: in instantiation of function template specialization 'au::can_scale_without_overflow<au::Quantity<au::Meters, int>>' requested here
          stdx::bool_constant<can_scale_without_overflow<Rep>(ScaleFactor{}, OVERFLOW_THRESHOLD)>> {
                              ^
au/code/au/stdx/type_traits.hh:36:25: note: in instantiation of template class 'au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>' requested here
struct conjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct conjunction<B, Bn...> : std::conditional_t<bool(B::value), conjunction<Bn...>, B> {};
                               ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
au/code/au/stdx/type_traits.hh:44:25: note: in instantiation of template class 'au::stdx::conjunction<std::is_integral<int>, au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct disjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:46:32: note: (skipping 7 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
struct disjunction<B, Bn...> : std::conditional_t<bool(B::value), B, disjunction<Bn...>> {};
                               ^
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
In file included from au/code/au/quantity.hh:20:
au/code/au/conversion_policy.hh:48:78: error: calling a private constructor of class 'au::Quantity<au::Meters, int>'
          stdx::bool_constant<can_scale_without_overflow<Rep>(ScaleFactor{}, OVERFLOW_THRESHOLD)>> {
                                                                             ^
au/code/au/stdx/type_traits.hh:36:25: note: in instantiation of template class 'au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>' requested here
struct conjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct conjunction<B, Bn...> : std::conditional_t<bool(B::value), conjunction<Bn...>, B> {};
                               ^
au/code/au/stdx/type_traits.hh:38:32: note: in instantiation of template class 'au::stdx::conjunction<au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
au/code/au/stdx/type_traits.hh:44:25: note: in instantiation of template class 'au::stdx::conjunction<std::is_integral<int>, au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>' requested here
struct disjunction<B> : B {};
                        ^
au/code/au/stdx/type_traits.hh:46:32: note: in instantiation of template class 'au::stdx::disjunction<au::stdx::conjunction<std::is_integral<int>, au::IsInteger<au::Magnitude<>>, au::detail::CanScaleThresholdWithoutOverflow<au::Quantity<au::Meters, int>, au::Magnitude<>>>>' requested here
struct disjunction<B, Bn...> : std::conditional_t<bool(B::value), B, disjunction<Bn...>> {};
                               ^
au/code/au/conversion_policy.hh:56:7: note: (skipping 6 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
    : stdx::disjunction<
      ^
au/code/au/quantity.hh:122:15: note: in instantiation of default argument for 'Quantity<au::Meters, int>' required here
    constexpr Quantity(Quantity<OtherUnit, OtherRep> other)  // NOLINT(runtime/explicit)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:490:16: note: while substituting deduced template arguments into function template 'Quantity' [with OtherUnit = au::Meters, OtherRep = int, Enable = (no value)]
        return {value};
               ^
au/code/au/quantity.hh:40:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    return QuantityMaker<UnitT>{}(value);
           ^
au/code/au/quantity_point.hh:287:39: note: in instantiation of function template specialization 'au::make_quantity<au::Meters, au::Quantity<au::Meters, int>>' requested here
        return QuantityPoint<Unit, T>{make_quantity<Unit>(value)};
                                      ^
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Quantity<au::Meters, int>>' requested here
    meters_pt(meters(51));
             ^
au/code/au/quantity.hh:400:15: note: declared private here
    constexpr Quantity(Rep value) : value_{value} {}
              ^
9 errors generated.

New error messages

In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:119:5: error: static_assert failed due to requirement 'IsValidRep<au::QuantityMaker<au::Radians>>::value' "Rep must meet our requirements for a rep"
    static_assert(IsValidRep<Rep>::value, "Rep must meet our requirements for a rep");
    ^             ~~~~~~~~~~~~~~~~~~~~~~
au/code/au/quantity.hh:498:33: note: in instantiation of template class 'au::Quantity<au::Radians, au::QuantityMaker<au::Radians>>' requested here
    constexpr Quantity<Unit, T> operator()(T value) const {
                                ^
au/code/au/au_test.cc:94:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Radians>::operator()<au::QuantityMaker<au::Radians>>' requested here
    radians(radians);
           ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:505:9: error: static_assert failed due to requirement 'is_not_already_a_quantity' "Input to QuantityMaker is already a Quantity"
        static_assert(is_not_already_a_quantity, "Input to QuantityMaker is already a Quantity");
        ^             ~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/au_test.cc:95:12: note: in instantiation of function template specialization 'au::QuantityMaker<au::Radians>::operator()<au::Radians, double>' requested here
    radians(radians(3.14));
           ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:17:
au/code/au/quantity.hh:511:9: error: static_assert failed due to requirement 'is_not_a_quantity_point' "Input to QuantityMaker is a QuantityPoint"
        static_assert(is_not_a_quantity_point, "Input to QuantityMaker is a QuantityPoint");
        ^             ~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/au_test.cc:96:11: note: in instantiation of function template specialization 'au::QuantityMaker<au::Meters>::operator()<au::Meters, int>' requested here
    meters(meters_pt(15));
          ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:18:
au/code/au/quantity_point.hh:299:9: error: static_assert failed due to requirement 'is_not_already_a_quantity_point' "Input to QuantityPointMaker is already a QuantityPoint"
        static_assert(is_not_already_a_quantity_point,
        ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
au/code/au/au_test.cc:97:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Meters, int>' requested here
    meters_pt(meters_pt(51));
             ^
In file included from au/code/au/au_test.cc:15:
In file included from au/code/au/au.hh:17:
In file included from au/code/au/chrono_interop.hh:20:
In file included from au/code/au/prefix.hh:18:
au/code/au/quantity_point.hh:293:9: error: static_assert failed due to requirement 'is_not_a_quantity' "Input to QuantityPointMaker is a Quantity"
        static_assert(is_not_a_quantity, "Input to QuantityPointMaker is a Quantity");
        ^             ~~~~~~~~~~~~~~~~~
au/code/au/au_test.cc:98:14: note: in instantiation of function template specialization 'au::QuantityPointMaker<au::Meters>::operator()<au::Meters, int>' requested here
    meters_pt(meters(51));
             ^
5 errors generated.