mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-31 19:04:27 +02:00
docs: "Basic Concepts" and "Interface Introduction" chapters updated
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
# Basic Concepts
|
||||
|
||||
The most important concepts in the **mp-units** library are `Dimension`, `QuantitySpec`, `Unit`,
|
||||
`Reference`, `Representation`, `Quantity`, and `QuantityPoint`:
|
||||
The most important concepts in the **mp-units** library are [`Dimension`](#Dimension),
|
||||
[`QuantitySpec`](#QuantitySpec), [`Unit`](#Unit), [`Reference`](#Reference),
|
||||
[`Representation`](#Representation), [`Quantity`](#Quantity), and [`QuantityPoint`](#QuantityPoint).
|
||||
|
||||
The tree provided below presents how those and a few other concepts depend on each other:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
@@ -29,7 +32,7 @@ flowchart TD
|
||||
`Dimension` concept matches a [dimension](../../appendix/glossary.md#dimension) of either a base
|
||||
or derived [quantity](../../appendix/glossary.md#quantity):
|
||||
|
||||
- [Base dimensions](../../appendix/glossary.md#base-dimension) are explicitly defined by a user
|
||||
- [Base dimensions](../../appendix/glossary.md#base-dimension) are explicitly defined by the user
|
||||
by inheriting from the instantiation of a `base_dimension` class template. It should be instantiated with
|
||||
a unique symbol identifier describing this dimension in a specific
|
||||
[system of quantities](../../appendix/glossary.md#system-of-quantities).
|
||||
@@ -44,8 +47,8 @@ or derived [quantity](../../appendix/glossary.md#quantity):
|
||||
`isq::dim_luminous_intensity` are the dimensions of base quantities in the
|
||||
[ISQ](../../appendix/glossary.md#isq).
|
||||
|
||||
IEC 80000 provides `iec80000::dim_traffic_intensity` base dimension to extend ISQ
|
||||
with information technology quantities.
|
||||
The implementation of IEC 80000 in this library provides `iec80000::dim_traffic_intensity`
|
||||
base dimension to extend ISQ with information technology quantities.
|
||||
|
||||
A `Dimension` can be defined by the user in the following way:
|
||||
|
||||
@@ -182,9 +185,9 @@ and when `T` is implicitly convertible to `V`.
|
||||
`si::second`, `si::metre`, `si::kilogram`, `si::ampere`, `si::kelvin`, `si::mole`, and `si::candela`
|
||||
are the base units of [SI](../../appendix/glossary.md#si).
|
||||
|
||||
`si::kilo<si::metre>` is a prefixed unit on length.
|
||||
`si::kilo<si::metre>` is a prefixed unit of length.
|
||||
|
||||
`si::radian`, `si::newton`, and `si::watt` are examples of named derived quantities within
|
||||
`si::radian`, `si::newton`, and `si::watt` are examples of named derived units within
|
||||
[SI](../../appendix/glossary.md#si).
|
||||
|
||||
`non_si::minute` is an example of a scaled unit of time.
|
||||
@@ -226,7 +229,7 @@ and is satisfied by:
|
||||
`si::second` is specified to measure `isq::time`.
|
||||
|
||||
Natural units typically do not have an associated quantity. For example, if we assume `c = 1`,
|
||||
a `natural::second` unit can be used to measure both `time` and `length`. In such case `speed`
|
||||
a `natural::second` unit can be used to measure both `time` and `length`. In such case, `speed`
|
||||
would be a [dimensionless quantity](../../appendix/glossary.md#dimensionless-quantity).
|
||||
|
||||
|
||||
@@ -241,7 +244,7 @@ units can be passed as an argument to a `prefixed_unit` class template.
|
||||
All units in the [SI](../../appendix/glossary.md#si) can be prefixed with SI-defined prefixes.
|
||||
|
||||
Some [off-system units](../../appendix/glossary.md#off-system-unit) like `non_si::day`
|
||||
can't be prefixed. To enforce that the following has to be provided:
|
||||
can't be prefixed. To enforce that, the following has to be provided:
|
||||
|
||||
```cpp
|
||||
template<> inline constexpr bool unit_can_be_prefixed<non_si::day> = false;
|
||||
@@ -259,7 +262,7 @@ concept with an associated quantity type implicitly convertible to `V`.
|
||||
or the quantity type associated with `T` may not be derived from the kind of `V`.
|
||||
|
||||
This condition is required to make `dimensionless[si::radian]` invalid as `si::radian` should
|
||||
be only used for `isq::angular_measure` which is a
|
||||
be only used for `isq::angular_measure`, which is a
|
||||
[nested quantity kind within the dimensionless quantities tree](dimensionless_quantities.md/#nested-quantity-kinds).
|
||||
|
||||
|
||||
@@ -296,11 +299,10 @@ A `Reference` can either be:
|
||||
|
||||
`ReferenceOf` concept is satisfied by references `T` that match the following value `V`:
|
||||
|
||||
| `V` | Condition |
|
||||
|----------------------|-----------------------------------------------------------------------------------------------|
|
||||
| `Dimension` | The dimension of a quantity specification satisfies [`DimensionOf<V>`](#DimensionOf) concept. |
|
||||
| `QuantitySpec` | The quantity specification satisfies [`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
|
||||
| `quantity_character` | The quantity specification has a character of `V`. |
|
||||
| `V` | Condition |
|
||||
|----------------|-----------------------------------------------------------------------------------------------|
|
||||
| `Dimension` | The dimension of a quantity specification satisfies [`DimensionOf<V>`](#DimensionOf) concept. |
|
||||
| `QuantitySpec` | The quantity specification satisfies [`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
|
||||
|
||||
|
||||
## `Representation<T>` { #Representation }
|
||||
@@ -324,8 +326,8 @@ with `true` for one or more of the following variable templates:
|
||||
|
||||
??? abstract "Examples"
|
||||
|
||||
If we want to use scalar types to express [vector quantities](character_of_a_quantity.md#defining-vector-and-tensor-quantities)
|
||||
(e.g. ignoring the "direction" of the vector) the following definition can be provided to enable such a behavior:
|
||||
If we want to use scalar types to also express [vector quantities](character_of_a_quantity.md#defining-vector-and-tensor-quantities)
|
||||
(e.g., ignoring the "direction" of the vector) the following definition can be provided to enable such a behavior:
|
||||
|
||||
```cpp
|
||||
template<class T>
|
||||
@@ -337,14 +339,14 @@ with `true` for one or more of the following variable templates:
|
||||
## `Quantity<T>` { #Quantity }
|
||||
|
||||
`Quantity` concept matches every [quantity](../../appendix/glossary.md#quantity) in the library and is
|
||||
satisfied by all types being or deriving from and instantiation of a `quantity` class template.
|
||||
satisfied by all types being or deriving from an instantiation of a `quantity` class template.
|
||||
|
||||
??? abstract "Examples"
|
||||
|
||||
All of `42 * m`, `42 * si::metre`, `42 * isq::height[m]`, and `isq::height(42 * m)` create a quantity
|
||||
and thus satisfy a `Quantity` concept.
|
||||
|
||||
A quantity type can also be specified explicitly (e.g. `quantity<si::metre, int>`,
|
||||
A quantity type can also be specified explicitly (e.g., `quantity<si::metre, int>`,
|
||||
`quantity<isq::height[m]>`).
|
||||
|
||||
### `QuantityOf<T, V>` { #QuantityOf }
|
||||
@@ -359,7 +361,7 @@ is `true`.
|
||||
the library. It is satisfied by either:
|
||||
|
||||
- All types derived from an `absolute_point_origin` class template.
|
||||
- All types derived from an `relative_point_origin` class template.
|
||||
- All types derived from a `relative_point_origin` class template.
|
||||
|
||||
??? abstract "Examples"
|
||||
|
||||
@@ -390,8 +392,8 @@ implicitly convertible from quantity specification `V`, which means that `V` mus
|
||||
then it can't be used as a point origin for _points_ of `isq::length` or `isq::width` as none of them
|
||||
is implicitly convertible to `isq::altitude`:
|
||||
|
||||
- not every "length" is an "altitude",
|
||||
- "width" is not compatible with "altitude".
|
||||
- not every _length_ is an _altitude_,
|
||||
- _width_ is not compatible with _altitude_.
|
||||
|
||||
|
||||
## `QuantityPoint<T>` { #QuantityPoint }
|
||||
|
@@ -10,10 +10,10 @@ inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
|
||||
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
|
||||
```
|
||||
|
||||
Please note that the above reuses the same identifier for a type and its object. The rationale
|
||||
Please note that the above reuses the same identifier for a type and its value. The rationale
|
||||
behind this is that:
|
||||
|
||||
- Users always work with objects and never have to spell such a type name.
|
||||
- Users always work with values and never have to spell such a type name.
|
||||
- The types appear in the compilation errors and during debugging.
|
||||
|
||||
!!! important
|
||||
@@ -33,17 +33,17 @@ to improve the user experience while debugging the program or analyzing the comp
|
||||
!!! note
|
||||
|
||||
Such a practice is rare in the industry. Some popular C++ physical units libraries
|
||||
generate enormously long error messages where even only the first line failed o fit
|
||||
generate enormously long error messages where even only the first line failed to fit
|
||||
on a slide with a tiny font.
|
||||
|
||||
|
||||
## Entities composability
|
||||
|
||||
Many physical units libraries (in C++ or any other programming language) assign strong types
|
||||
to library entities (e.g. derived units). While `metre_per_second` as a type may not look too
|
||||
to library entities (e.g., derived units). While `metre_per_second` as a type may not look too
|
||||
scary, consider, for example, units of angular momentum. If we followed this path, its
|
||||
[coherent unit](../../appendix/glossary.md#coherent-derived-unit) would look like
|
||||
`kilogram_metre_sq_per_second`. Now, consider how many scaled versions of this unit would you
|
||||
`kilogram_metre_sq_per_second`. Now, consider how many scaled versions of this unit you would
|
||||
predefine in the library to ensure that all users are happy with your choice?
|
||||
How expensive would it be from the implementation point of view?
|
||||
What about potential future standardization efforts?
|
||||
@@ -55,7 +55,7 @@ possible. For example, to create a quantity with a unit of speed, one may write:
|
||||
quantity<si::metre / si::second> q;
|
||||
```
|
||||
|
||||
In case we use such an unit often and would prefer to have a handy helper for it, we can
|
||||
In case we use such a unit often and would prefer to have a handy helper for it, we can
|
||||
always do something like this:
|
||||
|
||||
```cpp
|
||||
@@ -63,7 +63,7 @@ constexpr auto metre_per_second = si::metre / si::second;
|
||||
quantity<metre_per_second> q;
|
||||
```
|
||||
|
||||
or choose any shorter identifier of your choice.
|
||||
or choose any shorter identifier of our choice.
|
||||
|
||||
Coming back to the angular momentum case, thanks to the composability of units, a user can
|
||||
create such a quantity in the following way:
|
||||
@@ -74,13 +74,13 @@ auto q = la_vector{1, 2, 3} * isq::angular_momentum[kg * m2 / s];
|
||||
```
|
||||
|
||||
It is a much better solution. It is terse and easy to understand. Please also notice how
|
||||
easy it is to obtain any scaled version of such a unit (e.g. `mg * square(mm) / min`)
|
||||
easy it is to obtain any scaled version of such a unit (e.g., `mg * square(mm) / min`)
|
||||
without having to introduce hundreds of types to predefine them.
|
||||
|
||||
|
||||
## Value-based equations
|
||||
|
||||
The **mp-units** library is based on C++20, which greatly improves a user's experience. One of
|
||||
The **mp-units** library is based on C++20, significantly improving user experience. One of
|
||||
such improvements are value-based equations.
|
||||
|
||||
As we have learned above, the entities are being used as values in the code, and they compose.
|
||||
@@ -89,7 +89,7 @@ This is a huge improvement compared to what we can find in other physical units
|
||||
what we have to deal with when we want to write some equations for `std::ratio`.
|
||||
|
||||
For example, below are a few definitions of the SI derived units showing the power of C++20
|
||||
extensions to Non-Type Template Parameters, which allows us to directly pass a result of
|
||||
extensions to Non-Type Template Parameters, which allow us to directly pass a result of
|
||||
the value-based [unit equation](../../appendix/glossary.md#unit-equation) to a class template
|
||||
definition:
|
||||
|
||||
@@ -141,7 +141,7 @@ The same type identifier will be visible in the compilation error (in case it ha
|
||||
|
||||
### Identities
|
||||
|
||||
As mentioned above, equations can be done on dimensions, quantities, and units. Each such domain must
|
||||
As mentioned above, equations can be performed on dimensions, quantities, and units. Each such domain must
|
||||
introduce an identity object that can be used in the resulting expressions. Here is the list of
|
||||
identities used in the library:
|
||||
|
||||
@@ -152,7 +152,7 @@ identities used in the library:
|
||||
| `QuantitySpec` | `dimensionless` |
|
||||
| `Unit` | `one` |
|
||||
|
||||
In the equations, a user can explicitly refer to an identity object:
|
||||
In the equations, a user can explicitly refer to an identity object. For example:
|
||||
|
||||
```cpp
|
||||
constexpr auto my_unit = one / second;
|
||||
@@ -172,7 +172,7 @@ constexpr auto my_unit = one / second;
|
||||
|
||||
### Supported operations and their results
|
||||
|
||||
There are only a few operations that one can do on such entities and the result of each of them has
|
||||
There are only a few operations that one can do on such entities, and the result of each of them has
|
||||
its unique representation in the library:
|
||||
|
||||
| Operation | Resulting template expression arguments |
|
||||
@@ -208,7 +208,7 @@ the resulting expression template.
|
||||
```
|
||||
|
||||
This is probably the most important of all the steps, as it allows comparing types and enables
|
||||
the rest of simplification rules.
|
||||
the rest of the simplification rules.
|
||||
|
||||
2. **Aggregation**
|
||||
|
||||
@@ -263,13 +263,13 @@ Thanks to all of the features described above, a user may write the code like th
|
||||
|
||||
```cpp
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
auto speed = 60. * isq::speed[km / h];
|
||||
auto duration = 8 * s;
|
||||
auto acceleration = speed / duration;
|
||||
quantity speed = 60. * isq::speed[km / h];
|
||||
quantity duration = 8 * s;
|
||||
quantity acceleration = speed / duration;
|
||||
std::cout << "acceleration: " << acceleration << " (" << acceleration.in(m / s2) << ")\n";
|
||||
```
|
||||
|
||||
The `acceleration`, being the result of the above code, has the following type
|
||||
The `acceleration` quantity, being the result of the above code, has the following type
|
||||
(after stripping the `mp_units` namespace for brevity):
|
||||
|
||||
```text
|
||||
|
Reference in New Issue
Block a user