| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | # Interface Introduction
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## New style of definitions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The **mp-units** library decided to use a rather unusual pattern to define entities. | 
					
						
							| 
									
										
										
										
											2023-08-03 21:23:34 +02:00
										 |  |  | Here is how we define `metre` and `second` [SI](../../appendix/glossary.md#si) base units: | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre; | 
					
						
							|  |  |  | inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | Please note that the above reuses the same identifier for a type and its value. The rationale | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | behind this is that: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | - Users always work with values and never have to spell such a type name. | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | - The types appear in the compilation errors and during debugging. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 11:33:30 +02:00
										 |  |  | !!! important | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     To improve compiler errors' readability and make it easier to correlate them with | 
					
						
							|  |  |  |     a user's written code, a new idiom in the library is to use the same identifier for | 
					
						
							|  |  |  |     a type and its instance. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-07 20:42:22 +02:00
										 |  |  | ## Strong types instead of aliases
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Let's look again at the above units definitions. Another important point to notice is that | 
					
						
							|  |  |  | all the types describing entities in the library are short, nicely named identifiers | 
					
						
							|  |  |  | that derive from longer, more verbose class template instantiations. This is really important | 
					
						
							|  |  |  | to improve the user experience while debugging the program or analyzing the compilation error. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | !!! note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Such a practice is rare in the industry. Some popular C++ physical units libraries | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  |     generate enormously long error messages where even only the first line failed to fit | 
					
						
							| 
									
										
										
										
											2023-07-07 20:42:22 +02:00
										 |  |  |     on a slide with a tiny font. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | ## Entities composability
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Many physical units libraries (in C++ or any other programming language) assign strong types | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | to library entities (e.g., derived units). While `metre_per_second` as a type may not look too | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | scary, consider, for example, units of angular momentum. If we followed this path, its | 
					
						
							| 
									
										
										
										
											2023-08-03 21:23:34 +02:00
										 |  |  | [coherent unit](../../appendix/glossary.md#coherent-derived-unit) would look like | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | `kilogram_metre_sq_per_second`. Now, consider how many scaled versions of this unit you would | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 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? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This is why in **mp-units**, we put a strong requirement to make everything as composable as | 
					
						
							|  |  |  | possible. For example, to create a quantity with a unit of speed, one may write: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | quantity<si::metre / si::second> q; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | In case we use such a unit often and would prefer to have a handy helper for it, we can | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | always do something like this: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | constexpr auto metre_per_second = si::metre / si::second; | 
					
						
							|  |  |  | quantity<metre_per_second> q; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | or choose any shorter identifier of our choice. | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Coming back to the angular momentum case, thanks to the composability of units, a user can | 
					
						
							|  |  |  | create such a quantity in the following way: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | using namespace mp_units::si::unit_symbols; | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | easy it is to obtain any scaled version of such a unit (e.g., `mg * square(mm) / min`) | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | without having to introduce hundreds of types to predefine them. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-07 20:42:22 +02:00
										 |  |  | ## Value-based equations
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | The **mp-units** library is based on C++20, significantly improving user experience. One of | 
					
						
							| 
									
										
										
										
											2023-07-07 20:42:22 +02:00
										 |  |  | such improvements are value-based equations. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | As we have learned above, the entities are being used as values in the code, and they compose. | 
					
						
							|  |  |  | Moreover, derived entities can be defined in the library using such value-based equations. | 
					
						
							|  |  |  | This is a huge improvement compared to what we can find in other physical units libraries or | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | extensions to Non-Type Template Parameters, which allow us to directly pass a result of | 
					
						
							| 
									
										
										
										
											2023-08-03 21:23:34 +02:00
										 |  |  | the value-based [unit equation](../../appendix/glossary.md#unit-equation) to a class template | 
					
						
							| 
									
										
										
										
											2023-07-07 20:42:22 +02:00
										 |  |  | definition: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton; | 
					
						
							|  |  |  | inline constexpr struct pascal : named_unit<"Pa", newton / square(metre)> {} pascal; | 
					
						
							|  |  |  | inline constexpr struct joule : named_unit<"J", newton * metre> {} joule; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | ## Expression templates
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The previous chapter provided a rationale for not having predefined types for derived entities. | 
					
						
							|  |  |  | In many libraries, such an approach results in long and unreadable compilation errors, as | 
					
						
							|  |  |  | framework-generated types are typically far from being easy to read and understand. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The **mp-units** library greatly improves the user experience by extensively using | 
					
						
							|  |  |  | expression templates. Such expressions are used consistently throughout the entire library | 
					
						
							|  |  |  | to describe the results of: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 21:23:34 +02:00
										 |  |  | - [dimension equation](../../appendix/glossary.md#dimension-equation) - the result is put into | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  |   the `derived_dimension<>` class template | 
					
						
							| 
									
										
										
										
											2023-08-03 21:23:34 +02:00
										 |  |  | - [quantity equation](../../appendix/glossary.md#quantity-equation) - the result is put into | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  |   the `derived_quantity_spec<>` class template | 
					
						
							| 
									
										
										
										
											2023-08-03 21:23:34 +02:00
										 |  |  | - [unit equation](../../appendix/glossary.md#unit-equation) - the result is put into the | 
					
						
							|  |  |  |   `derived_unit<>` class template | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | For example, if we take the above-defined base units and put the results of their division into | 
					
						
							|  |  |  | the quantity class template like this: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | quantity<metre / second> q; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | we will observe the following type in the debugger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | (gdb) ptype q | 
					
						
							|  |  |  | type = class mp_units::quantity<mp_units::derived_unit<metre, mp_units::per<second>>(), double> [with Rep = double] { | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The same type identifier will be visible in the compilation error (in case it happens). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 11:33:30 +02:00
										 |  |  | !!! important | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Expressions templates are extensively used throughout the library to improve the readability | 
					
						
							|  |  |  |     of the resulting types. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Identities
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | As mentioned above, equations can be performed on dimensions, quantities, and units. Each such domain must | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | introduce an identity object that can be used in the resulting expressions. Here is the list of | 
					
						
							|  |  |  | identities used in the library: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | | Domain Concept |    Identity     | | 
					
						
							|  |  |  | |----------------|:---------------:| | 
					
						
							|  |  |  | | `Dimension`    | `dimension_one` | | 
					
						
							|  |  |  | | `QuantitySpec` | `dimensionless` | | 
					
						
							|  |  |  | | `Unit`         |      `one`      | | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | In the equations, a user can explicitly refer to an identity object. For example: | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | constexpr auto my_unit = one / second; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-06 12:53:18 -06:00
										 |  |  | !!! note | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-06 12:53:18 -06:00
										 |  |  |     Another way to achieve the same result is to call an `inverse()` function: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ```cpp | 
					
						
							|  |  |  |     constexpr auto my_unit = inverse(second); | 
					
						
							|  |  |  |     ``` | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-06 12:53:18 -06:00
										 |  |  |     Both cases will result in the same expression template being generated and put into the wrapper | 
					
						
							|  |  |  |     class template. | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Supported operations and their results
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | There are only a few operations that one can do on such entities, and the result of each of them has | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | its unique representation in the library: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | |                   Operation                   | Resulting template expression arguments | | 
					
						
							|  |  |  | |:---------------------------------------------:|:---------------------------------------:| | 
					
						
							|  |  |  | |                    `A * B`                    |                 `A, B`                  | | 
					
						
							|  |  |  | |                    `B * A`                    |                 `A, B`                  | | 
					
						
							|  |  |  | |                    `A * A`                    |              `power<A, 2>`              | | 
					
						
							|  |  |  | |               `{identity} * A`                |                   `A`                   | | 
					
						
							|  |  |  | |               `A * {identity}`                |                   `A`                   | | 
					
						
							|  |  |  | |                    `A / B`                    |               `A, per<B>`               | | 
					
						
							|  |  |  | |                    `A / A`                    |              `{identity}`               | | 
					
						
							|  |  |  | |               `A / {identity}`                |                   `A`                   | | 
					
						
							|  |  |  | |               `{identity} / A`                |          `{identity}, per<A>`           | | 
					
						
							|  |  |  | |                  `pow<2>(A)`                  |              `power<A, 2>`              | | 
					
						
							|  |  |  | |             `pow<2>({identity})`              |              `{identity}`               | | 
					
						
							|  |  |  | |          `sqrt(A)` or `pow<1, 2>(A)`          |            `power<A, 1, 2>`             | | 
					
						
							|  |  |  | | `sqrt({identity})` or `pow<1, 2>({identity})` |              `{identity}`               | | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Simplifying the resulting expression templates
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To limit the length and improve the readability of generated types, there are many rules to simplify | 
					
						
							|  |  |  | the resulting expression template. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1. **Ordering** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The resulting comma-separated arguments of multiplication are always sorted according to | 
					
						
							|  |  |  |     a specific predicate. This is why: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ```cpp | 
					
						
							|  |  |  |     static_assert(A * B == B * A); | 
					
						
							|  |  |  |     static_assert(std::is_same_v<decltype(A * B), decltype(B * A)>); | 
					
						
							|  |  |  |     ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-10 20:24:23 +02:00
										 |  |  |     This is probably the most important of all the steps, as it allows comparing types and enables | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  |     the rest of the simplification rules. | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 2. **Aggregation** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     In case two of the same identifiers are found next to each other on the argument list they | 
					
						
							|  |  |  |     will be aggregated in one entry: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     |              Before              |      After       | | 
					
						
							|  |  |  |     |:--------------------------------:|:----------------:| | 
					
						
							|  |  |  |     |              `A, A`              |  `power<A, 2>`   | | 
					
						
							|  |  |  |     |         `A, power<A, 2>`         |  `power<A, 3>`   | | 
					
						
							|  |  |  |     |  `power<A, 1, 2>, power<A, 2>`   | `power<A, 5, 2>` | | 
					
						
							|  |  |  |     | `power<A, 1, 2>, power<A, 1, 2>` |       `A`        | | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3. **Simplification** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     In case two of the same identifiers are found in the numerator and denominator argument lists; | 
					
						
							|  |  |  |     they are being simplified into one entry: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     |        Before         |        After         | | 
					
						
							|  |  |  |     |:---------------------:|:--------------------:| | 
					
						
							|  |  |  |     |      `A, per<A>`      |     `{identity}`     | | 
					
						
							|  |  |  |     | `power<A, 2>, per<A>` |         `A`          | | 
					
						
							|  |  |  |     | `power<A, 3>, per<A>` |    `power<A, 2>`     | | 
					
						
							|  |  |  |     | `A, per<power<A, 2>>` | `{identity}, per<A>` | | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 4. **Repacking** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     In case an expression uses two results of other operations, the components of its arguments are repacked | 
					
						
							|  |  |  |     into one resulting type and simplified there. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     For example, assuming: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ```cpp | 
					
						
							|  |  |  |     constexpr auto X = A / B; | 
					
						
							|  |  |  |     ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     then: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     | Operation | Resulting template expression arguments | | 
					
						
							|  |  |  |     |:---------:|:---------------------------------------:| | 
					
						
							|  |  |  |     |  `X * B`  |                   `A`                   | | 
					
						
							|  |  |  |     |  `X * A`  |          `power<A, 2>, per<B>`          | | 
					
						
							|  |  |  |     |  `X * X`  |     `power<A, 2>, per<power<B, 2>>`     | | 
					
						
							|  |  |  |     |  `X / X`  |              `{identity}`               | | 
					
						
							|  |  |  |     |  `X / A`  |          `{identity}, per<B>`           | | 
					
						
							|  |  |  |     |  `X / B`  |          `A, per<power<B, 2>>`          | | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Example
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Thanks to all of the features described above, a user may write the code like this one: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | using namespace mp_units::si::unit_symbols; | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | quantity speed = 60. * isq::speed[km / h]; | 
					
						
							|  |  |  | quantity duration = 8 * s; | 
					
						
							|  |  |  | quantity acceleration = speed / duration; | 
					
						
							| 
									
										
										
										
											2023-08-23 16:46:15 +02:00
										 |  |  | std::cout << "acceleration: " << acceleration << " (" << acceleration.in(m / s2) << ")\n"; | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-25 21:39:09 +02:00
										 |  |  | The `acceleration` quantity, being the result of the above code, has the following type | 
					
						
							| 
									
										
										
										
											2023-06-23 15:19:08 +02:00
										 |  |  | (after stripping the `mp_units` namespace for brevity): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```text | 
					
						
							|  |  |  | quantity<reference<derived_quantity_spec<isq::speed, per<isq::time>>{}, derived_unit<si::kilo_<si::metre{}>, per<non_si::hour, si::second>>{}>{}, int> | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | and the text output presents: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```text | 
					
						
							|  |  |  | acceleration: 7.5 km h⁻¹ s⁻¹ (2.08333 m/s²) | 
					
						
							|  |  |  | ``` |