forked from mpusz/mp-units
feat: quantities can now be multiplied and divided by units
This commit is contained in:
@@ -16,10 +16,9 @@ static_assert(1 * h == 3600 * s);
|
||||
static_assert(1 * km + 1 * m == 1001 * m);
|
||||
|
||||
// derived quantities
|
||||
inline constexpr auto kmph = km / h;
|
||||
static_assert(1 * km / (1 * s) == 1000 * (m / s));
|
||||
static_assert(2 * kmph * (2 * h) == 4 * km);
|
||||
static_assert(2 * km / (2 * kmph) == 1 * h);
|
||||
static_assert(1 * km / (1 * s) == 1000 * m / s);
|
||||
static_assert(2 * km / h * (2 * h) == 4 * km);
|
||||
static_assert(2 * km / (2 * km / h) == 1 * h);
|
||||
|
||||
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::international::unit_symbols;
|
||||
|
||||
constexpr quantity v1 = 110 * (km / h);
|
||||
constexpr quantity v1 = 110 * km / h;
|
||||
constexpr quantity v2 = 70 * mph;
|
||||
constexpr quantity v3 = avg_speed(220. * isq::distance[km], 2 * h);
|
||||
constexpr quantity v4 = avg_speed(isq::distance(140. * mi), 2 * h);
|
||||
|
||||
@@ -92,47 +92,6 @@ In the **mp-units** library, both a number and a unit have to always be explicit
|
||||
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?
|
||||
|
||||
In the initial design of this library, the resulting type of division of two quantities was their
|
||||
|
||||
@@ -67,14 +67,9 @@ quantity q = make_quantity<si::metre>(42);
|
||||
Sometimes it might be awkward to type some derived units:
|
||||
|
||||
```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
|
||||
wrapper for it with:
|
||||
|
||||
|
||||
@@ -212,9 +212,9 @@ either:
|
||||
The following does not work:
|
||||
|
||||
```cpp
|
||||
Quantity auto q1 = 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 auto q1 = 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};
|
||||
```
|
||||
|
||||
In all the cases above, the SI unit `m / s` has an associated scalar quantity of `isq::length / isq::time`.
|
||||
|
||||
@@ -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:
|
||||
|
||||
```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(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:
|
||||
|
||||
```cpp
|
||||
if (q1 / q2 != 0 * (m / s))
|
||||
if (q1 / q2 != 0 * m / s)
|
||||
// ...
|
||||
```
|
||||
|
||||
|
||||
@@ -291,12 +291,12 @@ in the denominator), or never in which case a parenthesis will be added to enclo
|
||||
units.
|
||||
|
||||
```cpp
|
||||
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 %aq}", 1 * (m / s)); // 1 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 * (kg / m / s2)); // 1 kg 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 %aq}", 1 * m / s); // 1 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 * kg / m / s2); // 1 kg m⁻¹ s⁻²
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```cpp
|
||||
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 %q}", 1 * kg * m2 / s2); // 1 kg m²/s²
|
||||
std::println("{:%Q %dq}", 1 * kg * m2 / s2); // 1 kg⋅m²/s²
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user