coherent_derived_unit and custom prefixes support added

This commit is contained in:
Mateusz Pusz committed 2019-10-17 10:16:44 +02:00
1 parent 9a9abca81d
commit 3e30c779a6
29 files changed
+261 -115

No files matched your search

+54 -26
View File
@@ -1,5 +1,6 @@
# `mp-units` - A Units Library for C++
## Summary
`Units` is a compile-time enabled Modern C++ library that provides compile-time dimensional
@@ -71,6 +72,7 @@ constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto
}
```
## Basic Concepts
Below UML diagram shows the most important entities in the library design and how they relate to
@@ -256,35 +258,35 @@ struct unit : downcast_base<unit<D, R>> {
};
```
All units are created with a `derived_unit` helper:
Coherent derived units (units with `ratio<1>`) are created with a `coherent_derived_unit` helper:
```cpp
template<typename Child, fixed_string Symbol, Dimension D, typename Prefix = no_prefix>
struct coherent_derived_unit;
```
The above type exposes public `symbol` and `prefix` member types used to print unit symbol names.
For example to define the base unit of `length`:
```cpp
struct metre : coherent_derived_unit<metre, "m", length, si_prefix> {};
```
Again, similarly to `derived_dimension`, the first class template parameter is a CRTP idiom used
to provide downcasting facility (described below).
All other units are created with a `derived_unit` helper:
```cpp
template<typename Child, fixed_string Symbol, typename...>
struct derived_unit;
```
For example to define the base unit of `length`:
The above type exposes public `symbol` member type used to print unit symbol names.
```cpp
struct metre : derived_unit<metre, "m", length> {};
```
Again, similarly to `derived_dimension`, the first class template parameter is a CRTP idiom used
to provide downcasting facility (described below).
`derived_unit` has a few partial useful specializations:
- helper to create a base unit of a specified dimension
```cpp
template<typename Child, fixed_string Symbol, Dimension D>
struct derived_unit<Child, Symbol, D>;
```
```cpp
struct metre : derived_unit<metre, "m", length> {};
```
- helper to create other units for a specified dimension
`derived_unit` has a few useful partial specializations:
- helper to create non-coherent units for a specified dimension
```cpp
template<typename Child, fixed_string Symbol, Dimension D, Ratio R>
@@ -295,7 +297,7 @@ struct derived_unit<Child, Symbol, D, R>;
struct yard : derived_unit<yard, "yd", length, ratio<9'144, 10'000>> {};
```
- helper to create a unit with a SI prefix
- helper to create a named unit with a SI prefix
```cpp
template<typename Child, fixed_string Symbol, Unit U>
@@ -428,6 +430,22 @@ template<Scalar ToRep, typename U, typename Rep>
[[nodiscard]] constexpr quantity<U, ToRep> quantity_cast(const quantity<U, Rep>& q);
```
#### `operator<<`
The library tries its best to print a correct unit of the quantity. This is why it performs a series
of checks:
1. If the user predefined a unit with a `coherent_derived_unit` or `derived_unit` class templates,
the symbol provided by the user will be used (i.e. `60 W`).
2. If a quantity has an unknown unit for a dimension predefined by the user with `derived_dimension`,
the symbol of a coherent unit of this dimension will be used. Additionally:
- if `Prefix` template parameter of a `coherent_derived_unit` is different than `no_prefix` then
the prefix symbol (i.e. `8 cJ`) defined by the specialization of `units::prefix_symbol` will be
aded wherever possible (`Ratio` matches the prefix ratio),
- otherwise, non-standard ratio (i.e. `2 [60]Hz`) will be printed.
3. If a quantity has an unknown dimension, the symbols of base dimensions will be used to construct
a unit symbol (i.e. `2 m/kg^2`). In this case no prefix symbols are added.
## Strong types instead of aliases, and type downcasting facility
Most of the important design decisions in the library are dictated by the requirement of providing
@@ -658,14 +676,24 @@ In order to extend the library with custom dimensions the user has to:
concept DigitalInformation = units::QuantityOf<T, digital_information>;
```
4. Define units and register them to a downcasting facility:
4. If non-SI prefixes should be applied to the unit symbol, define a new prefix tag and provide
`prefix_symbol` specializations to provide their text representation:
```cpp
struct bit : units::derived_unit<bit, "b", digital_information> {};
struct data_prefix;
template<> inline constexpr std::string_view units::prefix_symbol<data_prefix, units::ratio< 1'024>> = "Ki";
template<> inline constexpr std::string_view units::prefix_symbol<data_prefix, units::ratio<1'048'576>> = "Mi";
```
5. Define units and register them to a downcasting facility:
```cpp
struct bit : units::coherent_derived_unit<bit, "b", digital_information, data_prefix> {};
struct byte : units::derived_unit<byte, "B", digital_information, units::ratio<8>> {};
```
5. Provide user-defined literals for the most important units:
6. Provide user-defined literals for the most important units:
```cpp
inline namespace literals {