feat: quantities can now be multiplied and divided by units

This commit is contained in:
Mateusz Pusz
2023-09-29 21:40:24 -06:00
parent 476a68ce8e
commit b2423bfded
25 changed files with 79 additions and 118 deletions

View File

@ -63,10 +63,9 @@ static_assert(1 * h == 3600 * s);
static_assert(1 * km + 1 * m == 1001 * m); static_assert(1 * km + 1 * m == 1001 * m);
// derived quantities // derived quantities
inline constexpr auto kmph = km / h; static_assert(1 * km / (1 * s) == 1000 * m / s);
static_assert(1 * km / (1 * s) == 1000 * (m / s)); static_assert(2 * km / h * (2 * h) == 4 * km);
static_assert(2 * kmph * (2 * h) == 4 * km); static_assert(2 * km / (2 * km / h) == 1 * h);
static_assert(2 * km / (2 * kmph) == 1 * h);
static_assert(2 * m * (3 * m) == 6 * m2); static_assert(2 * m * (3 * m) == 6 * m2);
@ -103,7 +102,7 @@ int main()
using namespace mp_units::si::unit_symbols; using namespace mp_units::si::unit_symbols;
using namespace mp_units::international::unit_symbols; using namespace mp_units::international::unit_symbols;
constexpr quantity v1 = 110 * (km / h); constexpr quantity v1 = 110 * km / h;
constexpr quantity v2 = 70 * mph; constexpr quantity v2 = 70 * mph;
constexpr quantity v3 = avg_speed(220. * isq::distance[km], 2 * h); constexpr quantity v3 = avg_speed(220. * isq::distance[km], 2 * h);
constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * h); constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * h);

View File

@ -16,10 +16,9 @@ static_assert(1 * h == 3600 * s);
static_assert(1 * km + 1 * m == 1001 * m); static_assert(1 * km + 1 * m == 1001 * m);
// derived quantities // derived quantities
inline constexpr auto kmph = km / h; static_assert(1 * km / (1 * s) == 1000 * m / s);
static_assert(1 * km / (1 * s) == 1000 * (m / s)); static_assert(2 * km / h * (2 * h) == 4 * km);
static_assert(2 * kmph * (2 * h) == 4 * km); static_assert(2 * km / (2 * km / h) == 1 * h);
static_assert(2 * km / (2 * kmph) == 1 * h);
static_assert(2 * m * (3 * m) == 6 * m2); static_assert(2 * m * (3 * m) == 6 * m2);
@ -59,7 +58,7 @@ int main()
using namespace mp_units::si::unit_symbols; using namespace mp_units::si::unit_symbols;
using namespace mp_units::international::unit_symbols; using namespace mp_units::international::unit_symbols;
constexpr quantity v1 = 110 * (km / h); constexpr quantity v1 = 110 * km / h;
constexpr quantity v2 = 70 * mph; constexpr quantity v2 = 70 * mph;
constexpr quantity v3 = avg_speed(220. * isq::distance[km], 2 * h); constexpr quantity v3 = avg_speed(220. * isq::distance[km], 2 * h);
constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * h); constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * h);

View File

@ -92,47 +92,6 @@ In the **mp-units** library, both a number and a unit have to always be explicit
form a quantity. form a quantity.
## Why `60 * km / h` does not compile?
The library design does not allow multiplying or dividing a quantity (the result of `60 * km`)
by another unit. This significantly limits the number of possible errors and surprises in the
quantity equations.
Consider the following expression:
```cpp
auto q = 60 * km / 2 * h;
```
Looks like `30 km/h`, right? But it is not. If the above code was allowed, it would result
in `30 km⋅h`. In case you want to divide `60 * km` by `2 * h` a parenthesis is needed:
```cpp
auto q = 60 * km / (2 * h);
```
Another surprising issue could result from the following code:
```cpp
template<typename T>
auto make_length(T v) { return v * si::metre; }
auto v = 42;
auto q = make_length(v);
```
The above might look like a good idea, but consider what would happen in the user provided
an already existing quantity:
```cpp
auto v = 42 * m;
auto q = make_length(v);
```
Fortunately, with the current design, such issues are detected at compile-time as
multiplying or dividing a quantity by a unit is not be supported.
## Why a dimensionless quantity is not just a fundamental arithmetic type? ## Why a dimensionless quantity is not just a fundamental arithmetic type?
In the initial design of this library, the resulting type of division of two quantities was their In the initial design of this library, the resulting type of division of two quantities was their

View File

@ -67,14 +67,9 @@ quantity q = make_quantity<si::metre>(42);
Sometimes it might be awkward to type some derived units: Sometimes it might be awkward to type some derived units:
```cpp ```cpp
quantity speed = 60 * (km / h); quantity speed = 60 * km / h;
``` ```
!!! note
Please note that `60 * km / h` will not compile. To read more about the rationale for such
a design please check our [FAQ](faq.md#why-dont-we-use-udls-to-create-a-quantity).
In case such a unit is used a lot in the project, a user can easily provide a nicely named In case such a unit is used a lot in the project, a user can easily provide a nicely named
wrapper for it with: wrapper for it with:

View File

@ -212,9 +212,9 @@ either:
The following does not work: The following does not work:
```cpp ```cpp
Quantity auto q1 = la_vector{1, 2, 3} * (m / s); Quantity auto q1 = la_vector{1, 2, 3} * m / s;
Quantity auto q2 = isq::velocity(la_vector{1, 2, 3} * (m / s)); Quantity auto q2 = isq::velocity(la_vector{1, 2, 3} * m / s);
quantity<isq::velocity[m/s]> q3{la_vector{1, 2, 3} * (m / s)}; quantity<isq::velocity[m/s]> q3{la_vector{1, 2, 3} * m / s};
``` ```
In all the cases above, the SI unit `m / s` has an associated scalar quantity of `isq::length / isq::time`. In all the cases above, the SI unit `m / s` has an associated scalar quantity of `isq::length / isq::time`.

View File

@ -136,7 +136,7 @@ However, suppose we multiply or divide quantities of the same or different types
number by a quantity. In that case, we most probably will end up in a quantity of yet another type: number by a quantity. In that case, we most probably will end up in a quantity of yet another type:
```cpp ```cpp
static_assert(120 * km / (2 * h) == 60 * (km / h)); static_assert(120 * km / (2 * h) == 60 * km / h);
static_assert(isq::width(2 * m) * isq::length(2 * m) == isq::area(4 * m2)); static_assert(isq::width(2 * m) * isq::length(2 * m) == isq::area(4 * m2));
static_assert(50 / isq::time(1 * s) == isq::frequency(50 * Hz)); static_assert(50 / isq::time(1 * s) == isq::frequency(50 * Hz));
``` ```
@ -283,7 +283,7 @@ every time when we want to ensure that we deal with a non-zero or positive value
We could implement such checks in the following way: We could implement such checks in the following way:
```cpp ```cpp
if (q1 / q2 != 0 * (m / s)) if (q1 / q2 != 0 * m / s)
// ... // ...
``` ```

View File

@ -291,12 +291,12 @@ in the denominator), or never in which case a parenthesis will be added to enclo
units. units.
```cpp ```cpp
std::println("{:%Q %q}", 1 * (m / s)); // 1 m/s std::println("{:%Q %q}", 1 * m / s); // 1 m/s
std::println("{:%Q %q}", 1 * (kg / m / s2)); // 1 kg m⁻¹ s⁻² std::println("{:%Q %q}", 1 * kg / m / s2); // 1 kg m⁻¹ s⁻²
std::println("{:%Q %aq}", 1 * (m / s)); // 1 m/s std::println("{:%Q %aq}", 1 * m / s); // 1 m/s
std::println("{:%Q %aq}", 1 * (kg / m / s2)); // 1 kg/(m s²) std::println("{:%Q %aq}", 1 * kg / m / s2); // 1 kg/(m s²)
std::println("{:%Q %nq}", 1 * (m / s)); // 1 m s⁻¹ std::println("{:%Q %nq}", 1 * m / s); // 1 m s⁻¹
std::println("{:%Q %nq}", 1 * (kg / m / s2)); // 1 kg m⁻¹ s⁻² std::println("{:%Q %nq}", 1 * kg / m / s2); // 1 kg m⁻¹ s⁻²
``` ```
Also, there are a few options to separate the units being multiplied: Also, there are a few options to separate the units being multiplied:
@ -319,6 +319,6 @@ to just use the `·` symbol as a separator.
The `units-unit-symbol-separator` token allows us to obtain the following outputs: The `units-unit-symbol-separator` token allows us to obtain the following outputs:
```cpp ```cpp
std::println("{:%Q %q}", 1 * (kg * m2 / s2)); // 1 kg m²/s² std::println("{:%Q %q}", 1 * kg * m2 / s2); // 1 kg m²/s²
std::println("{:%Q %dq}", 1 * (kg * m2 / s2)); // 1 kg⋅m²/s² std::println("{:%Q %dq}", 1 * kg * m2 / s2); // 1 kg⋅m²/s²
``` ```

View File

@ -82,11 +82,11 @@ int main()
auto bismark = Ship{.length{251. * m}, auto bismark = Ship{.length{251. * m},
.draft{9.3 * m}, .draft{9.3 * m},
.beam{36 * m}, .beam{36 * m},
.speed{56 * (km / h)}, .speed{56 * km / h},
.mass{50'300 * t}, .mass{50'300 * t},
.mainGuns{380 * mm}, .mainGuns{380 * mm},
.shellMass{800 * kg}, .shellMass{800 * kg},
.shellSpeed{820. * (m / s)}, .shellSpeed{820. * m / s},
.power{110.45 * kW}}; .power{110.45 * kW}};
// USS Iowa, using units from the foot-pound-second system // USS Iowa, using units from the foot-pound-second system
@ -97,7 +97,7 @@ int main()
.mass{57'540 * imperial::long_ton}, .mass{57'540 * imperial::long_ton},
.mainGuns{16 * in}, .mainGuns{16 * in},
.shellMass{2700 * lb}, .shellMass{2700 * lb},
.shellSpeed{2690. * (ft / s)}, .shellSpeed{2690. * ft / s},
.power{212'000 * hp}}; .power{212'000 * hp}};
// HMS King George V, using units from the foot-pound-second system // HMS King George V, using units from the foot-pound-second system
@ -108,7 +108,7 @@ int main()
.mass{42'245 * imperial::long_ton}, .mass{42'245 * imperial::long_ton},
.mainGuns{14 * in}, .mainGuns{14 * in},
.shellMass{1590 * lb}, .shellMass{1590 * lb},
.shellSpeed{2483. * (ft / s)}, .shellSpeed{2483. * ft / s},
.power{110'000 * hp}}; .power{110'000 * hp}};
print_details("KMS Bismark, defined in appropriate units from the SI system", bismark); print_details("KMS Bismark, defined in appropriate units from the SI system", bismark);

View File

@ -45,10 +45,10 @@ auto get_gliders()
using namespace mp_units::si::unit_symbols; using namespace mp_units::si::unit_symbols;
MP_UNITS_DIAGNOSTIC_PUSH MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_MISSING_BRACES MP_UNITS_DIAGNOSTIC_IGNORE_MISSING_BRACES
static const std::array gliders = {glider{"SZD-30 Pirat", {83 * (km / h), -0.7389 * (m / s)}}, static const std::array gliders = {glider{"SZD-30 Pirat", {83 * km / h, -0.7389 * m / s}},
glider{"SZD-51 Junior", {80 * (km / h), -0.6349 * (m / s)}}, glider{"SZD-51 Junior", {80 * km / h, -0.6349 * m / s}},
glider{"SZD-48 Jantar Std 3", {110 * (km / h), -0.77355 * (m / s)}}, glider{"SZD-48 Jantar Std 3", {110 * km / h, -0.77355 * m / s}},
glider{"SZD-56 Diana", {110 * (km / h), -0.63657 * (m / s)}}}; glider{"SZD-56 Diana", {110 * km / h, -0.63657 * m / s}}};
MP_UNITS_DIAGNOSTIC_POP MP_UNITS_DIAGNOSTIC_POP
return gliders; return gliders;
} }
@ -56,9 +56,9 @@ auto get_gliders()
auto get_weather_conditions() auto get_weather_conditions()
{ {
using namespace mp_units::si::unit_symbols; using namespace mp_units::si::unit_symbols;
static const std::array weather_conditions = {std::pair{"Good", weather{1900 * m, 4.3 * (m / s)}}, static const std::array weather_conditions = {std::pair{"Good", weather{1900 * m, 4.3 * m / s}},
std::pair{"Medium", weather{1550 * m, 2.8 * (m / s)}}, std::pair{"Medium", weather{1550 * m, 2.8 * m / s}},
std::pair{"Bad", weather{850 * m, 1.8 * (m / s)}}}; std::pair{"Bad", weather{850 * m, 1.8 * m / s}}};
return weather_conditions; return weather_conditions;
} }
@ -164,7 +164,7 @@ void example()
const auto waypoints = get_waypoints(); const auto waypoints = get_waypoints();
const auto weather_conditions = get_weather_conditions(); const auto weather_conditions = get_weather_conditions();
const task t = {waypoints[0], waypoints[1], waypoints[0]}; const task t = {waypoints[0], waypoints[1], waypoints[0]};
const aircraft_tow tow = {400 * m, 1.6 * (m / s)}; const aircraft_tow tow = {400 * m, 1.6 * m / s};
// TODO use C++20 date library when available // TODO use C++20 date library when available
// set `start_time` to 11:00 am today // set `start_time` to 11:00 am today
const timestamp start_time(std::chrono::system_clock::now()); const timestamp start_time(std::chrono::system_clock::now());

View File

@ -44,7 +44,7 @@ int main()
using namespace mp_units::si::unit_symbols; using namespace mp_units::si::unit_symbols;
using namespace mp_units::international::unit_symbols; using namespace mp_units::international::unit_symbols;
constexpr quantity v1 = 110 * (km / h); constexpr quantity v1 = 110 * km / h;
constexpr quantity v2 = 70 * mph; constexpr quantity v2 = 70 * mph;
constexpr quantity v3 = avg_speed(220. * km, 2 * h); constexpr quantity v3 = avg_speed(220. * km, 2 * h);
constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * isq::duration[h]); constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * isq::duration[h]);

View File

@ -53,7 +53,7 @@ int main()
using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>>; using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>>;
const auto interval = isq::duration(5 * s); const auto interval = isq::duration(5 * s);
const state initial = {30 * km, 40 * (m / s)}; const state initial = {30 * km, 40 * m / s};
const quantity<isq::position_vector[m], int> measurements[] = {30'110 * m, 30'265 * m, 30'740 * m, 30'750 * m, const quantity<isq::position_vector[m], int> measurements[] = {30'110 * m, 30'265 * m, 30'740 * m, 30'750 * m,
31'135 * m, 31'015 * m, 31'180 * m, 31'610 * m, 31'135 * m, 31'015 * m, 31'180 * m, 31'610 * m,
31'960 * m, 31'865 * m}; 31'960 * m, 31'865 * m};

View File

@ -53,7 +53,7 @@ int main()
using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>>; using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>>;
const auto interval = isq::duration(5 * s); const auto interval = isq::duration(5 * s);
const state initial = {30 * km, 50 * (m / s)}; const state initial = {30 * km, 50 * m / s};
const quantity<isq::position_vector[m], int> measurements[] = {30'160 * m, 30'365 * m, 30'890 * m, 31'050 * m, const quantity<isq::position_vector[m], int> measurements[] = {30'160 * m, 30'365 * m, 30'890 * m, 31'050 * m,
31'785 * m, 32'215 * m, 33'130 * m, 34'510 * m, 31'785 * m, 32'215 * m, 33'130 * m, 34'510 * m,
36'010 * m, 37'265 * m}; 36'010 * m, 37'265 * m};

View File

@ -53,7 +53,7 @@ int main()
using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>, using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>,
quantity<isq::acceleration[m / s2]>>; quantity<isq::acceleration[m / s2]>>;
const auto interval = isq::duration(5. * s); const auto interval = isq::duration(5. * s);
const state initial = {30 * km, 50 * (m / s), 0 * (m / s2)}; const state initial = {30 * km, 50 * m / s, 0 * m / s2};
const quantity<isq::position_vector[m], int> measurements[] = {30'160 * m, 30'365 * m, 30'890 * m, 31'050 * m, const quantity<isq::position_vector[m], int> measurements[] = {30'160 * m, 30'365 * m, 30'890 * m, 31'050 * m,
31'785 * m, 32'215 * m, 33'130 * m, 34'510 * m, 31'785 * m, 32'215 * m, 33'130 * m, 34'510 * m,

View File

@ -134,7 +134,7 @@ void example()
using namespace mp_units; using namespace mp_units;
using namespace mp_units::si::unit_symbols; using namespace mp_units::si::unit_symbols;
const auto a = isq::acceleration(measurement{9.8, 0.1} * (m / s2)); const auto a = isq::acceleration(measurement{9.8, 0.1} * m / s2);
const auto t = measurement{1.2, 0.1} * s; const auto t = measurement{1.2, 0.1} * s;
const QuantityOf<isq::velocity> auto v = a * t; const QuantityOf<isq::velocity> auto v = a * t;

View File

@ -53,7 +53,7 @@ QUANTITY_SPEC(horizontal_length, isq::length);
QUANTITY_SPEC(horizontal_area, isq::area, horizontal_length* isq::width); QUANTITY_SPEC(horizontal_area, isq::area, horizontal_length* isq::width);
inline constexpr auto g = 1 * si::standard_gravity; inline constexpr auto g = 1 * si::standard_gravity;
inline constexpr auto air_density = isq::mass_density(1.225 * (kg / m3)); inline constexpr auto air_density = isq::mass_density(1.225 * kg / m3);
class StorageTank { class StorageTank {
quantity<horizontal_area[m2]> base_; quantity<horizontal_area[m2]> base_;
@ -114,7 +114,7 @@ int main()
{ {
const quantity height = isq::height(200 * mm); const quantity height = isq::height(200 * mm);
auto tank = RectangularStorageTank(horizontal_length(1'000 * mm), isq::width(500 * mm), height); auto tank = RectangularStorageTank(horizontal_length(1'000 * mm), isq::width(500 * mm), height);
tank.set_contents_density(1'000 * isq::mass_density[kg / m3]); tank.set_contents_density(1'000 * kg / m3);
const auto duration = std::chrono::seconds{200}; const auto duration = std::chrono::seconds{200};
const quantity fill_time = value_cast<int>(quantity{duration}); // time since starting fill const quantity fill_time = value_cast<int>(quantity{duration}); // time since starting fill

View File

@ -164,7 +164,21 @@ template<typename Rep, Reference R>
return make_quantity<R{}>(std::forward<Rep>(lhs)); return make_quantity<R{}>(std::forward<Rep>(lhs));
} }
void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, Reference auto) = delete; template<typename Q, Reference R>
requires Quantity<std::remove_cvref_t<Q>>
[[nodiscard]] constexpr quantity<std::remove_cvref_t<Q>::reference * R{}, typename std::remove_cvref_t<Q>::rep>
operator*(Q&& q, R)
{
return make_quantity<std::remove_cvref_t<Q>::reference * R{}>(std::forward<Q>(q).numerical_value_);
}
template<typename Q, Reference R>
requires Quantity<std::remove_cvref_t<Q>>
[[nodiscard]] constexpr quantity<std::remove_cvref_t<Q>::reference / R{}, typename std::remove_cvref_t<Q>::rep>
operator/(Q&& q, R)
{
return make_quantity<std::remove_cvref_t<Q>::reference / R{}>(std::forward<Q>(q).numerical_value_);
}
[[nodiscard]] consteval AssociatedUnit auto common_reference(AssociatedUnit auto u1, AssociatedUnit auto u2, [[nodiscard]] consteval AssociatedUnit auto common_reference(AssociatedUnit auto u1, AssociatedUnit auto u2,
AssociatedUnit auto... rest) AssociatedUnit auto... rest)

View File

@ -311,7 +311,7 @@ TEST_CASE("vector of quantities", "[la]")
SECTION("to scalar magnitude") SECTION("to scalar magnitude")
{ {
const vector<quantity<isq::velocity[km / h], int>> v = {2 * (km / h), 3 * (km / h), 6 * (km / h)}; const vector<quantity<isq::velocity[km / h], int>> v = {2 * km / h, 3 * km / h, 6 * km / h};
const auto speed = get_magnitude<isq::speed>(v); const auto speed = get_magnitude<isq::speed>(v);
CHECK(speed.numerical_value_ref_in(km / h) == 7); CHECK(speed.numerical_value_ref_in(km / h) == 7);
} }
@ -384,12 +384,12 @@ TEST_CASE("vector of quantities", "[la]")
SECTION("multiply by scalar quantity") SECTION("multiply by scalar quantity")
{ {
const vector<quantity<isq::velocity[m / s], int>> v = {1 * (m / s), 2 * (m / s), 3 * (m / s)}; const vector<quantity<isq::velocity[m / s], int>> v = {1 * m / s, 2 * m / s, 3 * m / s};
SECTION("integral") SECTION("integral")
{ {
const auto mass = 2 * isq::mass[kg]; const auto mass = 2 * isq::mass[kg];
const auto result = vector<quantity<isq::momentum[N * s], int>>{2 * (N * s), 4 * (N * s), 6 * (N * s)}; const auto result = vector<quantity<isq::momentum[N * s], int>>{2 * N * s, 4 * N * s, 6 * N * s};
SECTION("derived_quantity_spec") SECTION("derived_quantity_spec")
{ {
@ -417,7 +417,7 @@ TEST_CASE("vector of quantities", "[la]")
SECTION("floating-point") SECTION("floating-point")
{ {
const auto mass = 0.5 * isq::mass[kg]; const auto mass = 0.5 * isq::mass[kg];
const auto result = vector<quantity<isq::momentum[N * s], double>>{0.5 * (N * s), 1. * (N * s), 1.5 * (N * s)}; const auto result = vector<quantity<isq::momentum[N * s], double>>{0.5 * N * s, 1. * N * s, 1.5 * N * s};
SECTION("derived_quantity_spec") SECTION("derived_quantity_spec")
{ {
@ -453,7 +453,7 @@ TEST_CASE("vector of quantities", "[la]")
SECTION("derived_quantity_spec") SECTION("derived_quantity_spec")
{ {
CHECK(pos / dur == vector<quantity<isq::velocity[km / h], int>>{15 * (km / h), 10 * (km / h), 5 * (km / h)}); CHECK(pos / dur == vector<quantity<isq::velocity[km / h], int>>{15 * km / h, 10 * km / h, 5 * km / h});
} }
// no way to apply quantity_cast to sub-components // no way to apply quantity_cast to sub-components
@ -461,7 +461,7 @@ TEST_CASE("vector of quantities", "[la]")
SECTION("quantity of velocity") SECTION("quantity of velocity")
{ {
const vector<quantity<isq::velocity[km / h], int>> v = pos / dur; const vector<quantity<isq::velocity[km / h], int>> v = pos / dur;
CHECK(v == vector<quantity<isq::velocity[km / h], int>>{15 * (km / h), 10 * (km / h), 5 * (km / h)}); CHECK(v == vector<quantity<isq::velocity[km / h], int>>{15 * km / h, 10 * km / h, 5 * km / h});
} }
} }
@ -471,8 +471,7 @@ TEST_CASE("vector of quantities", "[la]")
SECTION("derived_quantity_spec") SECTION("derived_quantity_spec")
{ {
CHECK(pos / dur == CHECK(pos / dur == vector<quantity<isq::velocity[km / h], double>>{60. * km / h, 40. * km / h, 20. * km / h});
vector<quantity<isq::velocity[km / h], double>>{60. * (km / h), 40. * (km / h), 20. * (km / h)});
} }
// no way to apply quantity_cast to sub-components // no way to apply quantity_cast to sub-components
@ -480,7 +479,7 @@ TEST_CASE("vector of quantities", "[la]")
SECTION("quantity of velocity") SECTION("quantity of velocity")
{ {
const vector<quantity<isq::velocity[km / h], double>> v = pos / dur; const vector<quantity<isq::velocity[km / h], double>> v = pos / dur;
CHECK(v == vector<quantity<isq::velocity[km / h], double>>{60. * (km / h), 40. * (km / h), 20. * (km / h)}); CHECK(v == vector<quantity<isq::velocity[km / h], double>>{60. * km / h, 40. * km / h, 20. * km / h});
} }
} }
} }
@ -490,7 +489,6 @@ TEST_CASE("vector of quantities", "[la]")
const vector<quantity<isq::position_vector[m], int>> r = {3 * m, 0 * m, 0 * m}; const vector<quantity<isq::position_vector[m], int>> r = {3 * m, 0 * m, 0 * m};
const vector<quantity<isq::force[N], int>> f = {0 * N, 10 * N, 0 * N}; const vector<quantity<isq::force[N], int>> f = {0 * N, 10 * N, 0 * N};
CHECK(cross_product(r, f) == CHECK(cross_product(r, f) == vector<quantity<isq::moment_of_force[N * m], int>>{0 * N * m, 0 * N * m, 30 * N * m});
vector<quantity<isq::moment_of_force[N * m], int>>{0 * (N * m), 0 * (N * m), 30 * (N * m)});
} }
} }

View File

@ -40,14 +40,14 @@ using namespace mp_units::cgs::unit_symbols;
static_assert(isq::length(100 * cm) == isq::length(1 * si::metre)); static_assert(isq::length(100 * cm) == isq::length(1 * si::metre));
static_assert(isq::mass(1000 * g) == isq::mass(1 * si::kilogram)); static_assert(isq::mass(1000 * g) == isq::mass(1 * si::kilogram));
static_assert(isq::time(1 * s) == isq::time(1 * si::second)); static_assert(isq::time(1 * s) == isq::time(1 * si::second));
static_assert(isq::speed(100 * (cm / s)) == isq::speed(1 * (si::metre / si::second))); static_assert(isq::speed(100 * cm / s) == isq::speed(1 * si::metre / si::second));
static_assert(isq::acceleration(100 * Gal) == isq::acceleration(1 * (si::metre / square(si::second)))); static_assert(isq::acceleration(100 * Gal) == isq::acceleration(1 * si::metre / square(si::second)));
static_assert(isq::force(100'000 * dyn) == isq::force(1 * si::newton)); static_assert(isq::force(100'000 * dyn) == isq::force(1 * si::newton));
static_assert(isq::energy(10'000'000 * erg) == isq::energy(1 * si::joule)); static_assert(isq::energy(10'000'000 * erg) == isq::energy(1 * si::joule));
static_assert(isq::power(10'000'000 * (erg / s)) == isq::power(1 * si::watt)); static_assert(isq::power(10'000'000 * erg / s) == isq::power(1 * si::watt));
static_assert(isq::pressure(10 * Ba) == isq::pressure(1 * si::pascal)); static_assert(isq::pressure(10 * Ba) == isq::pressure(1 * si::pascal));
static_assert(isq::dynamic_viscosity(10 * P) == isq::dynamic_viscosity(1 * (si::pascal * si::second))); static_assert(isq::dynamic_viscosity(10 * P) == isq::dynamic_viscosity(1 * si::pascal * si::second));
static_assert(isq::kinematic_viscosity(10'000 * St) == isq::kinematic_viscosity(1 * (square(si::metre) / si::second))); static_assert(isq::kinematic_viscosity(10'000 * St) == isq::kinematic_viscosity(1 * square(si::metre) / si::second));
static_assert(isq::wavenumber(1 * K) == isq::wavenumber(100 * (1 / si::metre))); static_assert(isq::wavenumber(1 * K) == isq::wavenumber(100 * (1 / si::metre)));
static_assert(10'000'000 * erg + 1 * si::joule == 2 * si::joule); static_assert(10'000'000 * erg + 1 * si::joule == 2 * si::joule);

View File

@ -114,7 +114,7 @@ static_assert(quantity{std::chrono::years{1}} == 31556952 * s);
// operators // operators
static_assert(quantity{1s} + 1 * s == 2 * s); static_assert(quantity{1s} + 1 * s == 2 * s);
static_assert(quantity{1s} + 1 * min == 61 * s); static_assert(quantity{1s} + 1 * min == 61 * s);
static_assert(10 * m / quantity{2s} == 5 * (m / s)); static_assert(10 * m / quantity{2s} == 5 * m / s);
static_assert(quantity_point{sys_seconds{1s}} + 1 * s == chrono_point_origin<std::chrono::system_clock> + 2 * s); static_assert(quantity_point{sys_seconds{1s}} + 1 * s == chrono_point_origin<std::chrono::system_clock> + 2 * s);
static_assert(quantity_point{sys_seconds{1s}} + 1 * min == chrono_point_origin<std::chrono::system_clock> + 61 * s); static_assert(quantity_point{sys_seconds{1s}} + 1 * min == chrono_point_origin<std::chrono::system_clock> + 61 * s);

View File

@ -36,10 +36,10 @@ using namespace mp_units::hep::unit_symbols;
using namespace mp_units::si::unit_symbols; using namespace mp_units::si::unit_symbols;
// mass // mass
static_assert(isq::mass(1'000 * (eV / c2)) == isq::mass(1 * (keV / c2))); static_assert(isq::mass(1'000 * eV / c2) == isq::mass(1 * keV / c2));
// momentum // momentum
static_assert(isq::momentum(1'000'000 * (eV / c)) == isq::momentum(1 * (MeV / c))); static_assert(isq::momentum(1'000'000 * eV / c) == isq::momentum(1 * MeV / c));
// area // area
static_assert(isq::area(1e28 * b) == isq::area(1. * m2)); static_assert(isq::area(1e28 * b) == isq::area(1. * m2));

View File

@ -47,6 +47,6 @@ static_assert(isq::length(10'000'000'000 * A) == 1 * si::metre);
static_assert(round<si::metre>(isq::length(1.L * pc)) == 30'856'775'814'913'673 * si::metre); static_assert(round<si::metre>(isq::length(1.L * pc)) == 30'856'775'814'913'673 * si::metre);
#endif #endif
static_assert(isq::speed(1 * c_0) == 299'792'458 * (si::metre / si::second)); static_assert(isq::speed(1 * c_0) == 299'792'458 * si::metre / si::second);
} // namespace } // namespace

View File

@ -92,8 +92,8 @@ static_assert(storage_capacity(1 * Pibit) == storage_capacity(1024 * Tibit));
static_assert(storage_capacity(1 * Eibit) == storage_capacity(1024 * Pibit)); static_assert(storage_capacity(1 * Eibit) == storage_capacity(1024 * Pibit));
// transfer rate // transfer rate
static_assert(storage_capacity(16 * B) / isq::duration(2 * s) == transfer_rate(8 * (B / s))); static_assert(storage_capacity(16 * B) / isq::duration(2 * s) == transfer_rate(8 * B / s));
static_assert(storage_capacity(120 * kB) / isq::duration(2 * min) == transfer_rate(1000 * (B / s))); static_assert(storage_capacity(120 * kB) / isq::duration(2 * min) == transfer_rate(1000 * B / s));
// modulation rate // modulation rate
static_assert(12 / isq::duration(2 * s) == modulation_rate(6 * Bd)); static_assert(12 / isq::duration(2 * s) == modulation_rate(6 * Bd));

View File

@ -594,8 +594,8 @@ static_assert(is_of_type<1. * km - 1. * m, quantity<si::metre, double>>);
static_assert(is_of_type<1 * m % (1 * km), quantity<si::metre, int>>); static_assert(is_of_type<1 * m % (1 * km), quantity<si::metre, int>>);
// different dimensions // different dimensions
static_assert(is_of_type<1 * (m / s) * (1 * s), quantity<si::metre, int>>); static_assert(is_of_type<1 * m / s * (1 * s), quantity<si::metre, int>>);
static_assert(is_of_type<1 * (m / s) * (1 * h), static_assert(is_of_type<1 * m / s * (1 * h),
quantity<derived_unit<struct si::hour, struct si::metre, per<struct si::second>>{}, int>>); quantity<derived_unit<struct si::hour, struct si::metre, per<struct si::second>>{}, int>>);
static_assert(is_of_type<1 * m * (1 * min), quantity<derived_unit<struct si::metre, struct si::minute>{}, int>>); static_assert(is_of_type<1 * m * (1 * min), quantity<derived_unit<struct si::metre, struct si::minute>{}, int>>);
static_assert(is_of_type<1 * s * (1 * Hz), quantity<derived_unit<struct si::hertz, struct si::second>{}, int>>); static_assert(is_of_type<1 * s * (1 * Hz), quantity<derived_unit<struct si::hertz, struct si::second>{}, int>>);

View File

@ -108,7 +108,7 @@ static_assert(is_of_type<42 * metre, quantity<metre, int>>);
static_assert(quantity<metre, int>::quantity_spec == length); static_assert(quantity<metre, int>::quantity_spec == length);
static_assert(is_of_type<42 * square(metre), quantity<square(metre), int>>); static_assert(is_of_type<42 * square(metre), quantity<square(metre), int>>);
static_assert(quantity<square(metre), int>::quantity_spec == pow<2>(length)); static_assert(quantity<square(metre), int>::quantity_spec == pow<2>(length));
static_assert(is_of_type<42 * (metre / second), quantity<metre / second, int>>); static_assert(is_of_type<42 * metre / second, quantity<metre / second, int>>);
static_assert(quantity<metre / second, int>::quantity_spec == length / time); static_assert(quantity<metre / second, int>::quantity_spec == length / time);
static_assert(is_of_type<42 * newton, quantity<newton, int>>); static_assert(is_of_type<42 * newton, quantity<newton, int>>);
static_assert(quantity<newton, int>::quantity_spec == mass * length / pow<2>(time)); static_assert(quantity<newton, int>::quantity_spec == mass * length / pow<2>(time));
@ -156,8 +156,6 @@ concept invalid_operations = requires {
requires !requires { s < 1 * time[second]; }; requires !requires { s < 1 * time[second]; };
requires !requires { 1 * time[second] + s; }; requires !requires { 1 * time[second] + s; };
requires !requires { 1 * time[second] - s; }; requires !requires { 1 * time[second] - s; };
requires !requires { 1 * time[second] * s; };
requires !requires { 1 * time[second] / s; };
requires !requires { 1 * time[second] == s; }; requires !requires { 1 * time[second] == s; };
requires !requires { 1 * time[second] < s; }; requires !requires { 1 * time[second] < s; };
}; };

View File

@ -417,7 +417,6 @@ concept invalid_operations = requires {
requires !requires { s == 1 * time[second]; }; requires !requires { s == 1 * time[second]; };
requires !requires { 1 * time[second] + s; }; requires !requires { 1 * time[second] + s; };
requires !requires { 1 * time[second] - s; }; requires !requires { 1 * time[second] - s; };
requires !requires { 1 * time[second] * s; };
requires !requires { 1 * time[second] == s; }; requires !requires { 1 * time[second] == s; };
requires !requires { 1 * time[second] < s; }; requires !requires { 1 * time[second] < s; };
}; };