diff --git a/example/glide_computer_example.cpp b/example/glide_computer_example.cpp index 5f270738..55f3dde9 100644 --- a/example/glide_computer_example.cpp +++ b/example/glide_computer_example.cpp @@ -35,10 +35,10 @@ auto get_gliders() UNITS_DIAGNOSTIC_PUSH UNITS_DIAGNOSTIC_IGNORE_MISSING_BRACES static const std::array gliders = { - glider{"SZD-30 Pirat", {velocity(83 * km / h), rate_of_climb(-0.7389 * m / s)}}, - glider{"SZD-51 Junior", {velocity(80 * km / h), rate_of_climb(-0.6349 * m / s)}}, - glider{"SZD-48 Jantar Std 3", {velocity(110 * km / h), rate_of_climb(-0.77355 * m / s)}}, - glider{"SZD-56 Diana", {velocity(110 * km / h), rate_of_climb(-0.63657 * m / s)}}}; + glider{"SZD-30 Pirat", {velocity(83 * (km / h)), rate_of_climb(-0.7389 * (m / s))}}, + glider{"SZD-51 Junior", {velocity(80 * (km / h)), rate_of_climb(-0.6349 * (m / s))}}, + glider{"SZD-48 Jantar Std 3", {velocity(110 * (km / h)), rate_of_climb(-0.77355 * (m / s))}}, + glider{"SZD-56 Diana", {velocity(110 * (km / h)), rate_of_climb(-0.63657 * (m / s))}}}; UNITS_DIAGNOSTIC_POP return gliders; } @@ -47,9 +47,9 @@ auto get_weather_conditions() { using namespace si::references; static const std::array weather_conditions = { - std::pair("Good", weather{height(1900 * m), rate_of_climb(4.3 * m / s)}), - std::pair("Medium", weather{height(1550 * m), rate_of_climb(2.8 * m / s)}), - std::pair("Bad", weather{height(850 * m), rate_of_climb(1.8 * m / s)})}; + std::pair("Good", weather{height(1900 * m), rate_of_climb(4.3 * (m / s))}), + std::pair("Medium", weather{height(1550 * m), rate_of_climb(2.8 * (m / s))}), + std::pair("Bad", weather{height(850 * m), rate_of_climb(1.8 * (m / s))})}; return weather_conditions; } @@ -147,7 +147,7 @@ void example() const auto waypoints = get_waypoints(); const auto weather_conditions = get_weather_conditions(); const task t = {waypoints[0], waypoints[1], waypoints[0]}; - const aircraft_tow tow = {height(400 * m), rate_of_climb(1.6 * m / s)}; + const aircraft_tow tow = {height(400 * m), rate_of_climb(1.6 * (m / s))}; // TODO use C++20 date library when available // set `start_time` to 11:00 am today const timestamp start_time(std::chrono::system_clock::now()); diff --git a/example/hello_units.cpp b/example/hello_units.cpp index 92e58772..33775b85 100644 --- a/example/hello_units.cpp +++ b/example/hello_units.cpp @@ -38,7 +38,7 @@ int main() using namespace units::isq::si::literals; using namespace units::isq::si::references; - constexpr Speed auto v1 = 110 * km / h; + constexpr Speed auto v1 = 110 * (km / h); constexpr Speed auto v2 = avg_speed(220_q_km, 2_q_h); constexpr Speed auto v3 = avg_speed(si::length(140), si::time(2)); #if UNITS_DOWNCAST_MODE == 0 diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index c47635ce..ec246f4f 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -404,14 +404,10 @@ template Q2> return ret(ret(lhs).count() - ret(rhs).count()); } -template - requires Quantity || QuantityValue -[[nodiscard]] constexpr Quantity auto operator*(const QuantityOrQuantityValue& lhs, reference) +template +[[nodiscard]] constexpr Quantity auto operator*(const Rep& lhs, reference) { - if constexpr (Quantity) - return lhs * quantity::one(); - else - return quantity(lhs); + return quantity(lhs); } template @@ -421,14 +417,10 @@ template return detail::make_quantity(lhs.count() * rhs.count()); } -template - requires Quantity || QuantityValue -[[nodiscard]] constexpr Quantity auto operator/(const QuantityOrQuantityValue& lhs, reference) +template +[[nodiscard]] constexpr Quantity auto operator/(const Rep& lhs, reference) { - if constexpr (Quantity) - return lhs / quantity::one(); - else - return lhs / quantity::one(); + return lhs / quantity::one(); } template diff --git a/src/core/include/units/reference.h b/src/core/include/units/reference.h index eead99e1..6b32e4a7 100644 --- a/src/core/include/units/reference.h +++ b/src/core/include/units/reference.h @@ -72,7 +72,7 @@ using reference_divide = detail::reference_divide_impl< * using namespace units::isq::si::references; * * auto d = 123 * m; - * auto v = 70 * km / h; + * auto v = 70 * (km / h); * @endcode * * Also, it is allowed to define custom quantity references from existing ones: @@ -89,15 +89,19 @@ struct reference { using dimension = D; using unit = U; -#if !UNITS_COMP_MSVC - template - requires Quantity || QuantityValue - friend constexpr Quantity auto operator*(const QuantityOrQuantityValue& lhs, reference); + // Hidden Friends + // Below friend functions are to be found via argument-dependent lookup only - template - requires Quantity || QuantityValue - friend constexpr Quantity auto operator/(const QuantityOrQuantityValue& lhs, reference); +#if !UNITS_COMP_MSVC + template + friend constexpr Quantity auto operator*(const Rep& lhs, reference); + + template + friend constexpr Quantity auto operator/(const Rep& lhs, reference); #endif + + friend void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, reference) = delete; + friend void /*Use `q / (1 * r)` rather than `q / r`.*/ operator/(Quantity auto, reference) = delete; }; template diff --git a/test/unit_test/static/quantity_kind_test.cpp b/test/unit_test/static/quantity_kind_test.cpp index 75734c08..25891b9e 100644 --- a/test/unit_test/static/quantity_kind_test.cpp +++ b/test/unit_test/static/quantity_kind_test.cpp @@ -194,8 +194,8 @@ static_assert(width{}.common() == 0 * m); // CTAD ///////// -static_assert(same(quantity_kind(rate_of_climb(0.01 * km / h)), - rate_of_climb(0.01 * km / h))); +static_assert(same(quantity_kind(rate_of_climb(0.01 * (km / h))), + rate_of_climb(0.01 * (km / h)))); //////////////////////////// @@ -237,8 +237,8 @@ static_assert(!constructible_or_convertible_from>(1.0 * mm)); static_assert(!constructible_or_convertible_from>(1.0 * m)); static_assert(!constructible_or_convertible_from>(1.0 * km)); static_assert(!constructible_or_convertible_from>(1 * s)); -static_assert(!constructible_or_convertible_from>(1 * m * m)); -static_assert(!constructible_or_convertible_from>(1 * m / s)); +static_assert(!constructible_or_convertible_from>(1 * (m * m))); +static_assert(!constructible_or_convertible_from>(1 * (m / s))); static_assert(construct_from_only>(1.0f * m).common() == 1 * m); @@ -293,8 +293,8 @@ static_assert(construct_from_only>(42s).co static_assert(!constructible_or_convertible_from>(1 * s)); -static_assert(!constructible_or_convertible_from>(1 * m * m)); -static_assert(!constructible_or_convertible_from>(1 * m / s)); +static_assert(!constructible_or_convertible_from>(1 * (m * m))); +static_assert(!constructible_or_convertible_from>(1 * (m / s))); static_assert(construct_from_only>(1.0 * cgs_cm).common() == 1 * cm); @@ -321,7 +321,7 @@ static_assert(construct_and_convert_from>(width>(width(1 * m)).common() == 1 * m); static_assert(!constructible_or_convertible_from>(height(1 * m))); -static_assert(!constructible_or_convertible_from>(width(1 * m) / m)); +static_assert(!constructible_or_convertible_from>(width(1 * m) / (1 * m))); static_assert(!constructible_or_convertible_from>(oranges(1))); @@ -336,7 +336,7 @@ static_assert(!constructible_or_convertible_from>(quantity_ static_assert(!constructible_or_convertible_from>(quantity_point(1 * km))); static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * m))); static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * km))); -static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * m * m))); +static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * (m * m)))); static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * s))); static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * s))); static_assert(!constructible_or_convertible_from>(1s)); @@ -431,9 +431,9 @@ template concept invalid_compound_assignments = requires(quantity_kind w, height h) { requires !requires { w += 1; }; requires !requires { w -= 1; }; - requires !requires { w *= 1 * km / m; }; - requires !requires { w /= 1 * km / m; }; - requires !requires { w %= 1 * km / m; }; + requires !requires { w *= 1 * (km / m); }; + requires !requires { w /= 1 * (km / m); }; + requires !requires { w %= 1 * (km / m); }; requires !requires { w += m; }; requires !requires { w -= m; }; requires !requires { w *= m; }; @@ -532,12 +532,12 @@ static_assert(same(quantity_kind, one, int>(2 static_assert(same(quantity_kind, one, double>(2.) * width(3 * m), width(6. * m))); -static_assert(same(height(2 * m) * (3 * Hz), rate_of_climb(6 * m / s))); -static_assert(same(height(2 * m) * (3. * Hz), rate_of_climb(6. * m / s))); -static_assert(same(height(2. * m) * (3 * Hz), rate_of_climb(6. * m / s))); -static_assert(same((2 * Hz) * height(3 * m), rate_of_climb(6 * m / s))); -static_assert(same((2 * Hz) * height(3. * m), rate_of_climb(6. * m / s))); -static_assert(same((2. * Hz) * height(3 * m), rate_of_climb(6. * m / s))); +static_assert(same(height(2 * m) * (3 * Hz), rate_of_climb(6 * (m / s)))); +static_assert(same(height(2 * m) * (3. * Hz), rate_of_climb(6. * (m / s)))); +static_assert(same(height(2. * m) * (3 * Hz), rate_of_climb(6. * (m / s)))); +static_assert(same((2 * Hz) * height(3 * m), rate_of_climb(6 * (m / s)))); +static_assert(same((2 * Hz) * height(3. * m), rate_of_climb(6. * (m / s)))); +static_assert(same((2. * Hz) * height(3 * m), rate_of_climb(6. * (m / s)))); static_assert(same(quantity_kind(2 * s) * (3 * Hz), quantity_kind, one, int>(6))); @@ -548,17 +548,17 @@ static_assert(same(apples(2) * quantity(2), apples(4))); static_assert(same(quantity(2) * apples(2), apples(4))); // clang-format off -static_assert(same(width(4 * m) * m, horizontal_area(4 * m * m))); -static_assert(same(width(2 * m) * width(2 * m), horizontal_area(4 * m * m))); -static_assert(same(width(2 * m) * width(2 * m), horizontal_area(4 * m * m))); -static_assert(same(width(2 * m) * width(2 * m), horizontal_area(4 * m * m))); +static_assert(same(width(4 * m) * (1 * m), horizontal_area(4 * (m * m)))); +static_assert(same(width(2 * m) * width(2 * m), horizontal_area(4 * (m * m)))); +static_assert(same(width(2 * m) * width(2 * m), horizontal_area(4 * (m * m)))); +static_assert(same(width(2 * m) * width(2 * m), horizontal_area(4 * (m * m)))); // clang-format on static_assert(same(apples(2) * apples(2), apples(4))); static_assert(same(apples(2) * (2 / apples(1)), apples(4))); -static_assert(same(width(4 * m) * mm, horizontal_area(4 * m * mm))); -static_assert(same(width(2 * m) * width(2 * m), horizontal_area(4 * m * m))); +static_assert(same(width(4 * m) * (1 * mm), horizontal_area(4 * (m * mm)))); +static_assert(same(width(2 * m) * width(2 * m), horizontal_area(4 * (m * m)))); static_assert(same(width(2 * m) * (1 / width(2 * m)), quantity_kind, one>(1))); @@ -601,9 +601,9 @@ static_assert( same(quantity_kind, one, double>(2.) / quantity_kind(3 * s), quantity_kind, hertz, double>(2 / 3. / s))); -static_assert(same(height(2 * m) / (3 * s), rate_of_climb(0 * m / s))); -static_assert(same(height(2 * m) / (3. * s), rate_of_climb(2 / 3. * m / s))); -static_assert(same(height(2. * m) / (3 * s), rate_of_climb(2. / 3 * m / s))); +static_assert(same(height(2 * m) / (3 * s), rate_of_climb(0 * (m / s)))); +static_assert(same(height(2 * m) / (3. * s), rate_of_climb(2 / 3. * (m / s)))); +static_assert(same(height(2. * m) / (3 * s), rate_of_climb(2. / 3 * (m / s)))); static_assert(same(width(2 * m) * dimensionless(3), width(6 * cm))); static_assert(same(dimensionless(2) * width(3 * m), width(6 * cm))); @@ -634,8 +634,8 @@ static_assert(same(width(8 * m) / width(2 * m), static_assert(same(apples(8) / apples(2), apples(4))); static_assert(same(apples(8) / (2 / apples(1)), apples(4))); -static_assert(same(horizontal_area(8 * m * m) / width(2 * m), width(4 * m))); -static_assert(same(horizontal_area(4 * m * m) / m, width(4 * m))); +static_assert(same(horizontal_area(8 * (m * m)) / width(2 * m), width(4 * m))); +static_assert(same(horizontal_area(4 * (m * m)) / (1 * m), width(4 * m))); static_assert(same(width(2 * m) % 3, width(2 * m))); static_assert(same(width(3 * m) % width(2 * m), width(1 * m))); @@ -709,8 +709,8 @@ concept invalid_equality = requires(quantity_kind w) { requires !requires { w == dimensionless(1.0); }; requires !requires { w != height(1 * m); }; requires !requires { w == height(1.0 * km); }; - requires !requires { w != horizontal_area(1 * m * m); }; - requires !requires { w == rate_of_climb(1.0 * km / h); }; + requires !requires { w != horizontal_area(1 * (m * m)); }; + requires !requires { w == rate_of_climb(1.0 * (km / h)); }; requires !requires { w != quantity_point(1 * m); }; requires !requires { w == quantity_point(1.0 * mm); }; requires !requires { w != quantity_point(quantity(1)); }; @@ -739,8 +739,8 @@ concept invalid_relational = requires(quantity_kind w) { requires !requires { w <= dimensionless(1.0); }; requires !requires { w >= height(1 * m); }; requires !requires { w > height(1.0 * km); }; - requires !requires { w <=> horizontal_area(1 * m * m); }; - requires !requires { w < rate_of_climb(1.0 * km / h); }; + requires !requires { w <=> horizontal_area(1 * (m * m)); }; + requires !requires { w < rate_of_climb(1.0 * (km / h)); }; requires !requires { w <= quantity_point(1 * m); }; requires !requires { w >= quantity_point(1.0 * mm); }; requires !requires { w > quantity_point(quantity(1)); }; diff --git a/test/unit_test/static/quantity_point_kind_test.cpp b/test/unit_test/static/quantity_point_kind_test.cpp index 57670569..50717cfe 100644 --- a/test/unit_test/static/quantity_point_kind_test.cpp +++ b/test/unit_test/static/quantity_point_kind_test.cpp @@ -283,7 +283,7 @@ static_assert(construct_from_only>(quantity_point(1.0 * static_assert(!constructible_or_convertible_from>(quantity_point(1 * mm))); static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * m))); static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * km))); -static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * m * m))); +static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * (m * m)))); static_assert(!constructible_or_convertible_from>(quantity_point(1.0 * s))); // clang-format off @@ -508,7 +508,7 @@ concept invalid_equality = requires(quantity_point_kind x) requires !requires { x == width(1.0 * km); }; requires !requires { x != height(1 * m); }; requires !requires { x == height(1.0 * km); }; - requires !requires { x == rate_of_climb(1.0 * km / h); }; + requires !requires { x == rate_of_climb(1.0 * (km / h)); }; requires !requires { x != quantity_point(1 * m); }; requires !requires { x == quantity_point(1.0 * mm); }; requires !requires { x != quantity_point(quantity(1)); }; @@ -543,7 +543,7 @@ concept invalid_relational = requires(quantity_point_kind requires !requires { x > width(1.0 * km); }; requires !requires { x <=> height(1 * m); }; requires !requires { x < height(1.0 * km); }; - requires !requires { x <= rate_of_climb(1.0 * km / h); }; + requires !requires { x <= rate_of_climb(1.0 * (km / h)); }; requires !requires { x >= quantity_point(1 * m); }; requires !requires { x > quantity_point(1.0 * mm); }; requires !requires { x <=> quantity_point(quantity(1)); }; diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index b1adbac4..8f0960e1 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -324,9 +324,9 @@ concept invalid_compound_assignments = requires() { requires !requires(length l) { l %= dimensionless(2); }; // TODO: accept non-truncating argument - requires !requires(length l) { l *= 1 * km / m; }; - requires !requires(length l) { l /= 1 * km / m; }; - requires !requires(length l) { l %= 1 * km / m; }; + requires !requires(length l) { l *= 1 * (km / m); }; + requires !requires(length l) { l /= 1 * (km / m); }; + requires !requires(length l) { l %= 1 * (km / m); }; // only quantities can be added or subtracted requires !requires(length l) { l += 2; }; @@ -559,8 +559,8 @@ static_assert((10_q_s * 2_q_kHz).count() == 20); // unit constants -static_assert(2_q_m * m == (2_q_m2)); -static_assert(2_q_m2 / m == (2_q_m)); +static_assert(2_q_m * (1 * m) == (2_q_m2)); +static_assert(2_q_m2 / (1 * m) == (2_q_m)); // dimensionless @@ -601,8 +601,8 @@ static_assert((quantity{std::uint8_t(0)} - quantity{std::uint8_t(1)}).count() == static_assert(is_same_v); -static_assert(quantity{2} * m == 2_q_m); -static_assert(quantity{2} / m == 2 / 1_q_m); +static_assert(quantity{2} * (1 * m) == 2_q_m); +static_assert(quantity{2} / (1 * m) == 2 / 1_q_m); /////////////////////// diff --git a/test/unit_test/static/unit_constants.cpp b/test/unit_test/static/unit_constants.cpp index 45e1e63f..86ceb728 100644 --- a/test/unit_test/static/unit_constants.cpp +++ b/test/unit_test/static/unit_constants.cpp @@ -55,41 +55,42 @@ concept invalid_operations = requires { requires !requires { s - s; }; requires !requires { s + 1_q_s; }; requires !requires { s - 1_q_s; }; + requires !requires { s * 1_q_s; }; + requires !requires { s / 1_q_s; }; requires !requires { 1_q_s + s; }; requires !requires { 1_q_s - s; }; + requires !requires { 1_q_s * s; }; + requires !requires { 1_q_s / s; }; }; static_assert(invalid_operations); -static_assert(2_q_m / s == 2_q_m_per_s); -static_assert(2 * m / s == 2_q_m_per_s); -static_assert(2 / s * m == 2_q_m_per_s); +static_assert(2_q_m / (1 * s) == 2_q_m_per_s); static_assert(2 * (m / s) == 2_q_m_per_s); +static_assert(2 / (s / m) == 2_q_m_per_s); -#if !(UNITS_COMP_GCC == 10 && UNITS_COMP_GCC_MINOR == 1) +#if !(UNITS_COMP_GCC == 10 && UNITS_COMP_GCC_MINOR == 1) // GCC 10.1.0 ICEs constexpr auto m_per_s = m / s; static_assert(2 * ::m_per_s == 2_q_m_per_s); #endif static_assert(120 * km / (2 * h) == 60_q_km_per_h); -static_assert(120 * km / 2 / h == 60_q_km_per_h); static_assert([] { const auto length{120}; const auto duration{2}; return length * km / (duration * h); }() == 60_q_km_per_h); static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); +static_assert(is_same_v); static_assert(1. / 4 * m2 == 1._q_m2 / 4); UNITS_DIAGNOSTIC_PUSH UNITS_DIAGNOSTIC_IGNORE_SHADOW constexpr bool test_hiding() { - Speed auto v0 = 10 * m / s; - signed s = 2; // hides ^ + Speed auto v0 = 10 * (m / s); + signed s = 2; // hides ^ Length auto v = 20 * m / s; - /* */ v0 = 10 * m / ::s; + /* */ v0 = 10 * (m / ::s); return !is_same_v; }