mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 02:17:16 +02:00
Merge branch 'master' of github.com:mpusz/units
This commit is contained in:
@ -333,6 +333,20 @@
|
||||
associated with a specific quantity ([quantity specification](#quantity_spec) and
|
||||
[unit](#unit)).
|
||||
|
||||
[`canonical representation of a unit, canonical unit`](#canonical-unit){ #canonical-unit }
|
||||
|
||||
: - A canonical representation of a unit consists of:
|
||||
- a reference unit being the result of extraction of all the intermediate
|
||||
[derived units](#derived-unit),
|
||||
- a magnitude being a product of all the prefixes and magnitudes of extracted scaled units.
|
||||
- All units having the same canonical unit are deemed equal.
|
||||
- All units having the same reference unit are convertible
|
||||
(their magnitude may differ and is used during conversion).
|
||||
|
||||
[`reference unit`](#reference-unit){ #reference-unit }
|
||||
|
||||
: See [canonical representation of a unit](#canonical-unit)
|
||||
|
||||
[`absolute quantity point origin`, `absolute point origin`](#absolute-point-origin){ #absolute-point-origin }
|
||||
|
||||
: - An explicit point on an axis of values of a specific [quantity](#quantity) type that serves
|
||||
|
@ -19,7 +19,7 @@ flowchart TD
|
||||
quantity_character["Quantity character"] --- QuantitySpec
|
||||
QuantitySpec --- Reference["Quantity reference"]
|
||||
Reference --- Quantity
|
||||
quantity_character --- Representation
|
||||
quantity_character -.- Representation
|
||||
Representation --- Quantity
|
||||
Quantity --- QuantityPoint["Quantity point"]
|
||||
PointOrigin["Point origin"] --- QuantityPoint
|
||||
|
@ -1,16 +1,18 @@
|
||||
# Simple and Typed Quantities
|
||||
|
||||
ISO specifies a quantity as:
|
||||
ISO defines a quantity as:
|
||||
|
||||
!!! quote
|
||||
|
||||
property of a phenomenon, body, or substance, where the property has a magnitude that can be expressed as a number and a reference
|
||||
property of a phenomenon, body, or substance, where the property has a magnitude
|
||||
that can be expressed as a number and a reference
|
||||
|
||||
After that, it says:
|
||||
|
||||
!!! quote
|
||||
|
||||
A reference can be a measurement unit, a measurement procedure, a reference material, or a combination of such.
|
||||
A reference can be a measurement unit, a measurement procedure, a reference material,
|
||||
or a combination of such.
|
||||
|
||||
## `quantity` class template
|
||||
|
||||
@ -22,9 +24,10 @@ template<Reference auto R,
|
||||
class quantity;
|
||||
```
|
||||
|
||||
The concept `Reference` is satisfied by either:
|
||||
The concept `Reference` is satisfied by a type that provides all the domain-specific metadata describing
|
||||
a quantity (besides the representation type and its value). Such a type can be either:
|
||||
|
||||
- a unit with an associated quantity type (e.g. `si::metre`)
|
||||
- a unit with an associated quantity type (e.g., `si::metre`, `m / s`),
|
||||
- a reference type explicitly specifying the quantity type and its unit.
|
||||
|
||||
!!! important
|
||||
@ -37,9 +40,10 @@ A reference type is implicitly created as a result of the following expression:
|
||||
constexpr auto ref = isq::length[m];
|
||||
```
|
||||
|
||||
The above example resulted in the following type `reference<isq::length(), si::metre()>` being instantiated.
|
||||
The above example results in the following type `reference<isq::length(), si::metre()>` being instantiated.
|
||||
|
||||
Based on this property, the **mp-units** library provides two modes of dealing with quantities.
|
||||
As we have two alternative options that satisfy the `Reference` concept in the **mp-units** library,
|
||||
we also have two modes of dealing with quantities.
|
||||
|
||||
|
||||
## Simple quantities
|
||||
@ -85,7 +89,7 @@ A car driving 110 km in 2 h has an average speed of 15.2778 m/s (55 km/h)
|
||||
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/zWe8ecf93)"
|
||||
|
||||
|
||||
### Easy to understand compilation error messages
|
||||
### Easy-to-understand compilation error messages
|
||||
|
||||
In case a user makes an error in a quantity equation and the result of the calculation
|
||||
will not match the function return type, the compiler will detect such an issue at
|
||||
@ -175,7 +179,7 @@ As we can see above, the compilation error is longer but still relatively easy t
|
||||
|
||||
Based on the previous example, it might seem that typed quantities are not that useful,
|
||||
more to type and provide harder-to-understand error messages. It might be true in some cases,
|
||||
but there are cases where they provide an additional level of safety.
|
||||
but there are scenarios where they offer an additional level of safety.
|
||||
|
||||
Let's see another example:
|
||||
|
||||
@ -292,7 +296,7 @@ Let's see another example:
|
||||
|
||||
In the above example, the highlighted call doesn't look that safe anymore in the case
|
||||
of simple quantities, right? Suppose someone, either by mistake or due to some refactoring,
|
||||
will call the function with invalid order of arguments. In that case, the program will compile
|
||||
will call the function with an invalid order of arguments. In that case, the program will compile
|
||||
fine but not work as expected.
|
||||
|
||||
Let's see what will happen if we reorder the arguments in the case of typed quantities:
|
||||
@ -303,7 +307,7 @@ auto tank = RectangularStorageTank(horizontal_length(1'000 * mm),
|
||||
isq::width(500 * mm));
|
||||
```
|
||||
|
||||
This time a compiler provides the following compilation error:
|
||||
This time, a compiler provides the following compilation error:
|
||||
|
||||
```text
|
||||
In function 'int main()':
|
||||
@ -319,7 +323,7 @@ note: no known conversion for argument 2 from 'mp_units::quantity<mp_units::re
|
||||
```
|
||||
|
||||
What about derived quantities? In the above example, you probably noticed that we also defined
|
||||
a custom `horizontal_area` quantity of kind `isq::area`. This quantity has the special property
|
||||
a custom `horizontal_area` quantity of kind `isq::area`. This quantity has the unique property
|
||||
of being implicitly constructible only from the result of the multiplication of quantities of
|
||||
`horizontal_area` and `isq::width` or the ones that implicitly convert to them.
|
||||
|
||||
@ -377,15 +381,15 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
As `isq::radius` is not convertible to either a `horizontal_length` or `isq::width`,
|
||||
the derived quantity of `pow<2>(radius)` can't be converted to `horizontal_area` as well.
|
||||
As `isq::radius` is not convertible to `horizontal_length`, the derived quantity of
|
||||
`pow<2>(radius)` can't be converted to `horizontal_area` as well.
|
||||
It would be unsafe to allow such a conversion as not all of the circles lie flat on the
|
||||
ground, right?
|
||||
|
||||
In such a case, the user has to explicitly force such an unsafe conversion with the
|
||||
help of a `quantity_cast()`. This function name is easy to spot in code reviews or while
|
||||
searching the project for problems if something goes sideways. In case of unexpected issues
|
||||
related to quantities, this should be the first function to look for.
|
||||
searching the project for problems if something goes sideways. In case of unexpected
|
||||
quantities-related issues, this should be the first function to look for.
|
||||
|
||||
!!! tip
|
||||
|
||||
@ -397,7 +401,7 @@ related to quantities, this should be the first function to look for.
|
||||
|
||||
In case you wonder which mode you should choose for your project, we have good news for you.
|
||||
Simple and typed quantity modes can be freely mixed with each other. When you use different
|
||||
quantities of the same kind (e.g. radius, wavelength, altitude, ...), you should probably
|
||||
quantities of the same kind (e.g., _radius_, _wavelength_, _altitude_, ...), you should probably
|
||||
reach for typed quantities to bring additional safety for those cases. Otherwise, just use
|
||||
simple mode for the remaining quantities. The **mp-units** library will do its best to protect
|
||||
your project based on the information provided.
|
||||
|
@ -33,10 +33,10 @@ Box my_box(2 * m, 3 * m, 1 * m);
|
||||
How do you like such an interface? It turns out that in most existing strongly-typed libraries
|
||||
this is often the best we can do :woozy_face:
|
||||
|
||||
Another typical question many users ask is how to deal with energy and moment of force.
|
||||
Another typical question many users ask is how to deal with _work_ and _torque_.
|
||||
Both of those have the same dimension but are different quantities.
|
||||
|
||||
Another question is what should be the result of:
|
||||
A similar issue is related to figuring out what should be the result of:
|
||||
|
||||
```cpp
|
||||
auto res = 1 * Hz + 1 * Bq + 1 * Bd;
|
||||
@ -44,20 +44,27 @@ auto res = 1 * Hz + 1 * Bq + 1 * Bd;
|
||||
|
||||
where:
|
||||
|
||||
- `Hz` (hertz) - unit of frequency
|
||||
- `Bq` (becquerel) - unit of activity
|
||||
- `Bd` (baud) - unit of modulation rate
|
||||
- `Hz` (hertz) - unit of _frequency_
|
||||
- `Bq` (becquerel) - unit of _activity_
|
||||
- `Bd` (baud) - unit of _modulation rate_
|
||||
|
||||
All of those quantities have the same dimension, namely $\mathsf{T}^{-1}$, but probably it
|
||||
is not wise to allow adding, subtracting, or comparing them, as they describe vastly different
|
||||
physical properties.
|
||||
|
||||
If the above example seems too abstract, let's consider a _fuel consumption_ (fuel _volume_
|
||||
divided by _distance_, e.g., `6.7 l/km`) and an _area_. Again, both have the same dimension
|
||||
$\mathsf{L}^{2}$, but probably it wouldn't be wise to allow adding, subtracting, or comparing
|
||||
a _fuel consumption_ of a car and the _area_ of a football field. Such an operation does not
|
||||
have any physical sense and should fail to compile.
|
||||
|
||||
!!! important
|
||||
|
||||
More than one quantity may be defined for the same dimension:
|
||||
|
||||
- quantities of _different kinds_ (e.g. frequency, modulation rate, activity, ...)
|
||||
- quantities of _the same kind_ (e.g. length, width, altitude, distance, radius, wavelength, position vector, ...)
|
||||
- quantities of **different kinds** (e.g. _frequency_, _modulation rate_, _activity_, ...)
|
||||
- quantities of **the same kind** (e.g. _length_, _width_, _altitude_, _distance_, _radius_,
|
||||
_wavelength_, _position vector_, ...)
|
||||
|
||||
It turns out that the above issues can't be solved correctly without proper modeling of
|
||||
a [system of quantities](../../appendix/glossary.md#system-of-quantities).
|
||||
@ -76,7 +83,7 @@ a [system of quantities](../../appendix/glossary.md#system-of-quantities).
|
||||
dimension**
|
||||
- Quantities of the **same dimension are not necessarily of the same kind**
|
||||
|
||||
The above quotes from ISO 80000 answer to all the issues above. Two quantities can't be
|
||||
The above quotes from ISO 80000 provide answers to all the issues above. Two quantities can't be
|
||||
added, subtracted, or compared unless they belong to the same [kind](../../appendix/glossary.md#kind).
|
||||
As frequency, activity, and modulation rate are different kinds, the expression provided above should
|
||||
not compile.
|
||||
@ -106,11 +113,12 @@ flowchart TD
|
||||
radius --- radius_of_curvature
|
||||
```
|
||||
|
||||
Each of the above quantities expresses some kind of length, and each can be measured with `si::metre`.
|
||||
However, each of them has different properties, usage, and sometimes even a different
|
||||
Each of the above quantities expresses some kind of _length_, and each can be measured with `si::metre`.
|
||||
However, each of them has different properties, usage, and sometimes even requires a different
|
||||
representation type (notice that `position_vector` and `displacement` are vector quantities).
|
||||
|
||||
Analyzing such a hierarchy can help us in defining arithmetics and conversion rules.
|
||||
Such a hierarchy helps us in defining arithmetics and conversion rules for various quantities of
|
||||
the same kind.
|
||||
|
||||
|
||||
## Defining quantities
|
||||
@ -206,14 +214,14 @@ For example, here is how the above quantity kind tree can be modeled in the libr
|
||||
|
||||
## Comparing, adding, and subtracting quantities
|
||||
|
||||
ISO 80000 explicitly states that `width` and `height` are quantities of the same kind, and as such they:
|
||||
ISO 80000 explicitly states that _width_ and _height_ are quantities of the same kind, and as such they:
|
||||
|
||||
- are mutually comparable
|
||||
- can be added and subtracted
|
||||
- are mutually comparable,
|
||||
- can be added and subtracted.
|
||||
|
||||
If we take the above for granted, the only reasonable result of `1 * width + 1 * height` is `2 * length`,
|
||||
where the result of `length` is known as a common quantity type. A result of such an equation is always
|
||||
the first common branch in a hierarchy tree of the same kind. For example:
|
||||
where the result of `length` is known as a **common quantity** type. A result of such an equation is always
|
||||
the first common node in a hierarchy tree of the same kind. For example:
|
||||
|
||||
```cpp
|
||||
static_assert(common_quantity_spec(isq::width, isq::height) == isq::length);
|
||||
@ -228,33 +236,33 @@ Based on the same hierarchy of quantities of kind length, we can define quantity
|
||||
|
||||
1. **Implicit conversions**
|
||||
|
||||
- every `width` is a `length`
|
||||
- every `radius` is a `width`
|
||||
- every _width_ is a _length_
|
||||
- every _radius_ is a _width_
|
||||
|
||||
```cpp
|
||||
static_assert(implicitly_convertible(isq::width, isq::length));
|
||||
static_assert(implicitly_convertible(isq::radius, isq::length));
|
||||
static_assert(implicitly_convertible(isq::radius, isq::width));
|
||||
static_assert(implicitly_convertible(isq::radius, isq::length));
|
||||
```
|
||||
|
||||
2. **Explicit conversions**
|
||||
|
||||
- not every `length` is a `width`
|
||||
- not every `width` is a `radius`
|
||||
- not every _length_ is a _width_
|
||||
- not every _width_ is a _radius_
|
||||
|
||||
```cpp
|
||||
static_assert(!implicitly_convertible(isq::length, isq::width));
|
||||
static_assert(!implicitly_convertible(isq::length, isq::radius));
|
||||
static_assert(!implicitly_convertible(isq::width, isq::radius));
|
||||
static_assert(!implicitly_convertible(isq::length, isq::radius));
|
||||
static_assert(explicitly_convertible(isq::length, isq::width));
|
||||
static_assert(explicitly_convertible(isq::length, isq::radius));
|
||||
static_assert(explicitly_convertible(isq::width, isq::radius));
|
||||
static_assert(explicitly_convertible(isq::length, isq::radius));
|
||||
```
|
||||
|
||||
3. **Explicit casts**
|
||||
|
||||
- `height` is not a `width`
|
||||
- both `height` and `width` are quantities of kind `length`
|
||||
- _height_ is not a _width_
|
||||
- both _height_ and _width_ are quantities of kind _length_
|
||||
|
||||
```cpp
|
||||
static_assert(!implicitly_convertible(isq::height, isq::width));
|
||||
@ -264,7 +272,7 @@ Based on the same hierarchy of quantities of kind length, we can define quantity
|
||||
|
||||
4. **No conversion**
|
||||
|
||||
- `time` has nothing in common with `length`
|
||||
- _time_ has nothing in common with _length_
|
||||
|
||||
```cpp
|
||||
static_assert(!implicitly_convertible(isq::time, isq::length));
|
||||
@ -286,12 +294,12 @@ The below presents some arbitrary hierarchy of derived quantities of kind energy
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
energy["energy\n(mass * length^2 / time^2)"]
|
||||
energy["energy\n(mass * length<sup>2</sup> / time<sup>2</sup>)"]
|
||||
energy --- mechanical_energy
|
||||
mechanical_energy --- potential_energy
|
||||
potential_energy --- gravitational_potential_energy["gravitational_potential_energy\n(mass * acceleration_of_free_fall * height)"]
|
||||
potential_energy --- elastic_potential_energy["elastic_potential_energy\n(spring_constant * amount_of_compression^2)"]
|
||||
mechanical_energy --- kinetic_energy["kinetic_energy\n(mass * speed^2)"]
|
||||
potential_energy --- elastic_potential_energy["elastic_potential_energy\n(spring_constant * amount_of_compression<sup>2</sup>)"]
|
||||
mechanical_energy --- kinetic_energy["kinetic_energy\n(mass * speed<sup>2</sup>)"]
|
||||
energy --- enthalpy
|
||||
enthalpy --- internal_energy[internal_energy, thermodynamic_energy]
|
||||
internal_energy --- Helmholtz_energy[Helmholtz_energy, Helmholtz_function]
|
||||
@ -301,21 +309,21 @@ flowchart TD
|
||||
|
||||
Notice, that even though all of those quantities have the same dimension and can be expressed
|
||||
in the same units, they have different [quantity equations](../../appendix/glossary.md#quantity-equation)
|
||||
used to create them implicitly:
|
||||
that can be used to create them implicitly:
|
||||
|
||||
- `energy` is the most generic one and thus can be created from base quantities of `mass`, `length`,
|
||||
and `time`. As those are also the roots of quantities of their kinds and all other quantities are
|
||||
implicitly convertible to them (we agreed on that "every `width` is a `length`" already), it means
|
||||
that an `energy` can be implicitly constructed from any quantity of mass, length, and time.
|
||||
- _energy_ is the most generic one and thus can be created from base quantities of _mass_, _length_,
|
||||
and _time_. As those are also the roots of quantities of their kinds and all other quantities from their
|
||||
trees are implicitly convertible to them (we agreed on that "every _width_ is a _length_" already),
|
||||
it means that an _energy_ can be implicitly constructed from any quantity of _mass_, _length_, and _time_:
|
||||
|
||||
```cpp
|
||||
static_assert(implicitly_convertible(isq::mass * pow<2>(isq::length) / pow<2>(isq::time), isq::energy));
|
||||
static_assert(implicitly_convertible(isq::mass * pow<2>(isq::height) / pow<2>(isq::time), isq::energy));
|
||||
```
|
||||
|
||||
- `mechanical_energy` is a more "specialized" quantity than `energy` (not every `energy` is
|
||||
a `mechanical_energy`). It is why an explicit cast is needed to convert from either `energy` or
|
||||
the results of its [quantity equation](../../appendix/glossary.md#quantity-equation).
|
||||
- _mechanical energy_ is a more "specialized" quantity than _energy_ (not every _energy_ is
|
||||
a _mechanical energy_). It is why an explicit cast is needed to convert from either _energy_ or
|
||||
the results of its [quantity equation](../../appendix/glossary.md#quantity-equation):
|
||||
|
||||
```cpp
|
||||
static_assert(!implicitly_convertible(isq::energy, isq::mechanical_energy));
|
||||
@ -326,10 +334,10 @@ used to create them implicitly:
|
||||
isq::mechanical_energy));
|
||||
```
|
||||
|
||||
- `gravitational_potential_energy` is not only even more specialized one but additionally,
|
||||
- _gravitational potential energy_ is not only even more specialized one but additionally,
|
||||
it is special in a way that it provides its own "constrained"
|
||||
[quantity equation](../../appendix/glossary.md#quantity-equation). Maybe not every
|
||||
`mass * pow<2>(length) / pow<2>(time)` is a `gravitational_potential_energy`, but every
|
||||
`mass * pow<2>(length) / pow<2>(time)` is a _gravitational potential energy_, but every
|
||||
`mass * acceleration_of_free_fall * height` is.
|
||||
|
||||
```cpp
|
||||
@ -372,7 +380,7 @@ Additionally, the result of operations on quantity kinds is also a quantity kind
|
||||
static_assert(same_type<kind_of<isq::length> / kind_of<isq::time>, kind_of<isq::length / isq::time>>);
|
||||
```
|
||||
|
||||
However, if at least one equation's operand is not a kind, the result becomes a "strong"
|
||||
However, if at least one equation's operand is not a quantity kind, the result becomes a "strong"
|
||||
quantity where all the kinds are converted to the hierarchy tree's root quantities:
|
||||
|
||||
```cpp
|
||||
|
@ -7,14 +7,14 @@ quantities and provide automated conversion factors between various compatible u
|
||||
|
||||
Probably all the libraries in the wild model the [SI](../../appendix/glossary.md#si)
|
||||
and many of them provide support for additional units belonging to various other systems
|
||||
(e.g. imperial).
|
||||
(e.g., imperial, cgs, etc).
|
||||
|
||||
|
||||
## Systems of Units are based on Systems of Quantities
|
||||
|
||||
[Systems of quantities](../../appendix/glossary.md#system-of-quantities) specify a set
|
||||
of quantities and equations relating to those quantities. Those equations do not take any
|
||||
unit or a numerical representation into account at all. In order to create a quantity,
|
||||
unit or a numerical representation into account at all. To create a quantity,
|
||||
we need to add those missing pieces of information. This is where
|
||||
a [system of units](../../appendix/glossary.md#system-of-units) kicks in.
|
||||
|
||||
@ -33,14 +33,14 @@ inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
|
||||
|
||||
The `kind_of<isq::length>` above states explicitly that this unit has
|
||||
an associated quantity kind. In other words, `si::metre` (and scaled units based
|
||||
on it) can be used to express the amount of any quantity of kind length.
|
||||
on it) can be used to express the amount of any quantity of kind _length_.
|
||||
|
||||
|
||||
## Units compose
|
||||
|
||||
One of the strongest points of the [SI](../../appendix/glossary.md#si) system
|
||||
One of the most vital points of the [SI](../../appendix/glossary.md#si) system
|
||||
is that its units compose. This allows providing thousands of different units for
|
||||
hundreds of various quantities with a really small set of predefined units
|
||||
hundreds of various quantities with a tiny set of predefined units
|
||||
and prefixes.
|
||||
|
||||
The same is modeled in the **mp-units** library, which also allows composing
|
||||
@ -51,9 +51,9 @@ predefined units to create a nearly infinite number of different
|
||||
quantity<si::metre / si::second> q;
|
||||
```
|
||||
|
||||
to express a quantity of speed. The resulting quantity type is implicitly inferred
|
||||
to express a quantity of _speed_. The resulting quantity type is implicitly inferred
|
||||
from the [unit equation](../../appendix/glossary.md#unit-equation) by repeating
|
||||
exactly the same operations on the associated quantity kinds.
|
||||
the same operations on the associated quantity kinds.
|
||||
|
||||
|
||||
## Many shades of the same unit
|
||||
@ -64,13 +64,13 @@ The [SI](../../appendix/glossary.md#si) provides the names for 22 common
|
||||
|
||||
Each such named [derived unit](../../appendix/glossary.md#derived-unit) is a result
|
||||
of a specific predefined [unit equation](../../appendix/glossary.md#unit-equation).
|
||||
For example, a unit of power quantity is defined in the library as:
|
||||
For example, a unit of _power_ quantity is defined in the library as:
|
||||
|
||||
```cpp
|
||||
inline constexpr struct watt : named_unit<"W", joule / second> {} watt;
|
||||
```
|
||||
|
||||
However, a power quantity can be expressed in other units as well. For example,
|
||||
However, a _power_ quantity can be expressed in other units as well. For example,
|
||||
the following:
|
||||
|
||||
```cpp
|
||||
@ -96,23 +96,26 @@ All of the above quantities are equivalent and mean exactly the same.
|
||||
## Constraining a derived unit to work only with a specific derived quantity
|
||||
|
||||
Some derived units are valid only for specific derived quantities. For example,
|
||||
SI specifies both `hertz` and `becquerel` derived units with the same unit equation `1 / s`.
|
||||
However, it also explicitly states:
|
||||
[SI](../../appendix/glossary.md#si) specifies both `hertz` and `becquerel` derived units
|
||||
with the same unit equation `1 / s`. However, it also explicitly states:
|
||||
|
||||
!!! quote "SI Brochure"
|
||||
|
||||
The hertz shall only be used for periodic phenomena and the becquerel shall only be used for
|
||||
stochastic processes in activity referred to a radionuclide.
|
||||
|
||||
The library allows constraining such units in the following way:
|
||||
The above means that the usage of `becquerel` as a unit of a _frequency_ quantity is an error.
|
||||
|
||||
The library allows constraining such units to work only with quantities of a specific kind in
|
||||
the following way:
|
||||
|
||||
```cpp
|
||||
inline constexpr struct hertz : named_unit<"Hz", one / second, kind_of<isq::frequency>> {} hertz;
|
||||
inline constexpr struct becquerel : named_unit<"Bq", one / second, kind_of<isq::activity>> {} becquerel;
|
||||
```
|
||||
|
||||
With the above, `hertz` can only be used for frequencies while becquerel should only be used for
|
||||
quantities of activity. This means that the following equation will not compile:
|
||||
With the above, `hertz` can only be used with _frequencies_, while `becquerel` should only be used with
|
||||
quantities of _activity_. This means that the following equation will not compile:
|
||||
|
||||
```cpp
|
||||
auto q = 1 * Hz + 1 * Bq; // Fails to compile
|
||||
@ -131,7 +134,7 @@ Implementation of `std::ratio` provided by all major compilers is able to expres
|
||||
16 of them. This is why, in the **mp-units**, we had to find an alternative way to represent
|
||||
unit magnitude in a more flexible way.
|
||||
|
||||
Each prefix is implemented as:
|
||||
Each prefix is implemented similarly to the following:
|
||||
|
||||
```cpp
|
||||
template<PrefixableUnit auto U> struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U> {};
|
||||
@ -145,7 +148,7 @@ way:
|
||||
inline constexpr auto qm = quecto<metre>;
|
||||
```
|
||||
|
||||
The usage of `mag_power` not only enables providing support for SI prefixes but it can also
|
||||
The usage of `mag_power` not only enables providing support for SI prefixes, but it can also
|
||||
efficiently represent any rational magnitude. For example, IEC 80000 prefixes used in the
|
||||
IT industry can be implemented as:
|
||||
|
||||
@ -157,10 +160,10 @@ template<PrefixableUnit auto U> inline constexpr yobi_<U> yobi;
|
||||
## Scaled units
|
||||
|
||||
In the [SI](../../appendix/glossary.md#si), all units are either base or derived units or prefixed
|
||||
versions of those. However, those are not the only options possible.
|
||||
versions of those. However, those are only some of the options possible.
|
||||
|
||||
For example, there is a list of [off-system units](../../appendix/glossary.md#off-system-unit)
|
||||
accepted for use with SI. All of those are scaled versions of the SI units with ratios that can't
|
||||
accepted for use with SI. Those are scaled versions of the SI units with ratios that can't
|
||||
be explicitly expressed with predefined SI prefixes. Those include units like minute, hour, or
|
||||
electronvolt:
|
||||
|
||||
|
@ -41,6 +41,15 @@ inline constexpr struct great_british_pound : named_unit<"GBP", kind_of<currency
|
||||
inline constexpr struct japanese_jen : named_unit<"JPY", kind_of<currency>> {} japanese_jen;
|
||||
// clang-format on
|
||||
|
||||
namespace unit_symbols {
|
||||
|
||||
inline constexpr auto EUR = euro;
|
||||
inline constexpr auto USD = us_dollar;
|
||||
inline constexpr auto GBP = great_british_pound;
|
||||
inline constexpr auto JPY = japanese_jen;
|
||||
|
||||
} // namespace unit_symbols
|
||||
|
||||
static_assert(!std::equality_comparable_with<quantity<euro, int>, quantity<us_dollar, int>>);
|
||||
|
||||
|
||||
@ -88,7 +97,9 @@ quantity_point<To, PO, Rep> exchange_to(quantity_point<From, PO, Rep> q)
|
||||
|
||||
int main()
|
||||
{
|
||||
quantity_point price_usd = zero + 100 * us_dollar;
|
||||
using namespace unit_symbols;
|
||||
|
||||
quantity_point price_usd = zero + 100 * USD;
|
||||
quantity_point price_euro = exchange_to<euro>(price_usd);
|
||||
|
||||
std::cout << price_usd.quantity_from(zero) << " -> " << price_euro.quantity_from(zero) << "\n";
|
||||
|
@ -262,16 +262,13 @@ struct is_one<struct one> : std::true_type {};
|
||||
/**
|
||||
* @brief A canonical representation of a unit
|
||||
*
|
||||
* A canonical representation of a unit consists of a `reference_unit` and its scaling
|
||||
* factor represented by the magnitude `mag`.
|
||||
*
|
||||
* `reference_unit` is a unit (possibly derived one) that consists only named base units.
|
||||
* All of the intermediate derived units are extracted, prefixes and magnitudes of scaled
|
||||
* units are stripped from them and accounted in the `mag`.
|
||||
* A canonical representation of a unit consists of:
|
||||
* - a reference unit being the result of extraction of all the intermediate derived units,
|
||||
* - a magnitude being a product of all the prefixes and magnitudes of extracted scaled units.
|
||||
*
|
||||
* All units having the same canonical unit are deemed equal.
|
||||
* All units having the same `reference_unit` are convertible (their `mag` may differ
|
||||
* and is the subject of conversion).
|
||||
* All units having the same reference unit are convertible (their magnitude may differ and
|
||||
* is used during conversion).
|
||||
*
|
||||
* @tparam U a unit to use as a `reference_unit`
|
||||
* @tparam M a Magnitude representing an absolute scaling factor of this unit
|
||||
|
Reference in New Issue
Block a user