mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 18:37:15 +02:00
Documentation update for 0.3.0
This commit is contained in:
13
README.md
13
README.md
@ -3,7 +3,7 @@
|
|||||||
[](https://ci.appveyor.com/project/mpusz/units)
|
[](https://ci.appveyor.com/project/mpusz/units)
|
||||||
[ ](https://bintray.com/mpusz/conan-mpusz/mp-units%3Ampusz/_latestVersion)
|
[ ](https://bintray.com/mpusz/conan-mpusz/mp-units%3Ampusz/_latestVersion)
|
||||||
|
|
||||||
# `units` - A Units Library for C++
|
# `mp-units` - A Units Library for C++
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ NOTE: This library as of now compiles correctly only with gcc-9.1 and newer.
|
|||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
|
|
||||||
- ???
|
- 0.3.0 Sep 16, 2019 (CppCon 2019 release)
|
||||||
- Applied the feedback from the Cologne evening session
|
- Applied the feedback from the Cologne evening session
|
||||||
- `upcasting_traits` renamed to `downcasting_traits`
|
- `upcasting_traits` renamed to `downcasting_traits`
|
||||||
- `Dimension` template parameter removed from quantity
|
- `Dimension` template parameter removed from quantity
|
||||||
@ -67,11 +67,18 @@ NOTE: This library as of now compiles correctly only with gcc-9.1 and newer.
|
|||||||
- Missing `operator*` added
|
- Missing `operator*` added
|
||||||
- Predefined dimensions moved to a dedicated directory
|
- Predefined dimensions moved to a dedicated directory
|
||||||
- `dimension_` prefix removed from names of derived dimensions
|
- `dimension_` prefix removed from names of derived dimensions
|
||||||
|
- cmcstl2 library updated to 2019.09.19
|
||||||
|
- `base_dimension` is a value provided as `const&` to the `exp` type
|
||||||
|
- integrated with Compiler Explorer
|
||||||
|
- gsl-lite deppendency removed
|
||||||
|
- Fractional dimension exponents support added
|
||||||
|
- `QuantityOf` concept introduced
|
||||||
|
- `quantity_cast<U, Rep>()` support added
|
||||||
|
|
||||||
- 0.2.0 July 18, 2019
|
- 0.2.0 July 18, 2019
|
||||||
- Added C++20 features supported by gcc-9.1 (std::remove_cvref_t, down with typename, std::type_identity)
|
- Added C++20 features supported by gcc-9.1 (std::remove_cvref_t, down with typename, std::type_identity)
|
||||||
- The design as described on C++Now 2019 talk (https://youtu.be/wKchCktZPHU)
|
- The design as described on C++Now 2019 talk (https://youtu.be/wKchCktZPHU)
|
||||||
- Compile-time performance opimisations (type_list, common_ratio, ratio, conditional_t)
|
- Compile-time performance optimisations (type_list, common_ratio, ratio, conditional_t)
|
||||||
|
|
||||||
- 0.1.0 May 18, 2019
|
- 0.1.0 May 18, 2019
|
||||||
- Initial library release
|
- Initial library release
|
||||||
|
142
doc/DESIGN.md
142
doc/DESIGN.md
@ -1,4 +1,4 @@
|
|||||||
# `units` - Physical Units Library for C++
|
# `mp-units` - A Units Library for C++
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
@ -58,13 +58,13 @@ There are C++ concepts provided for each such quantity type:
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept Length = Quantity<T> && std::same_as<typename T::dimension, length>;
|
concept Length = QuantityOf<T, length>;
|
||||||
```
|
```
|
||||||
|
|
||||||
With that we can easily write a function template like this:
|
With that we can easily write a function template like this:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
constexpr stde::units::Velocity auto avg_speed(units::Length auto d,stde::units::Time auto t)
|
constexpr units::Velocity auto avg_speed(units::Length auto d, units::Time auto t)
|
||||||
{
|
{
|
||||||
return d / t;
|
return d / t;
|
||||||
}
|
}
|
||||||
@ -94,28 +94,28 @@ concept Dimension =
|
|||||||
|
|
||||||
#### `Exponents`
|
#### `Exponents`
|
||||||
|
|
||||||
`units::exp` provides an information about a single base dimension and its exponent in a derived
|
`units::exp` provides an information about a single base dimension and its (possibly fractional)
|
||||||
dimension:
|
exponent in a derived dimension:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename BaseDimension, int Value>
|
template<const base_dimension& BaseDimension, int Num, int Den = 1>
|
||||||
struct exp {
|
struct exp {
|
||||||
using dimension = BaseDimension;
|
static constexpr const base_dimension& dimension = BaseDimension;
|
||||||
static constexpr int value = Value;
|
static constexpr int num = Num;
|
||||||
|
static constexpr int den = Den;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
where `BaseDimension` is a unique sortable compile-time value and for now is implemented as:
|
where `BaseDimension` is a unique sortable compile-time value:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<int UniqueValue>
|
struct base_dimension {
|
||||||
using dim_id = std::integral_constant<int, UniqueValue>;
|
const char* name;
|
||||||
|
};
|
||||||
|
constexpr bool operator==(const base_dimension& lhs, const base_dimension& rhs);
|
||||||
|
constexpr bool operator<(const base_dimension& lhs, const base_dimension& rhs);
|
||||||
```
|
```
|
||||||
|
|
||||||
but it is meant to be replaced with C++20 class `constexpr` values provided as non-type template
|
|
||||||
parameters (when feature will be available in a compiler) so that for example base dimension for
|
|
||||||
length will be expressed as `dimension<exp<"length", 1>>`.
|
|
||||||
|
|
||||||
`units::Exponent` concept is satisfied if provided type is an instantiation of `units::exp` class
|
`units::Exponent` concept is satisfied if provided type is an instantiation of `units::exp` class
|
||||||
template:
|
template:
|
||||||
|
|
||||||
@ -208,13 +208,32 @@ struct merge_dimension {
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<Dimension D, Ratio R>
|
template<Dimension D, Ratio R>
|
||||||
requires (R::num > 0)
|
requires (R::num * R::den > 0)
|
||||||
struct unit : downcast_base<unit<D, R>> {
|
struct unit : downcast_base<unit<D, R>> {
|
||||||
using dimension = D;
|
using dimension = D;
|
||||||
using ratio = R;
|
using ratio = R;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For example to define the base unit of `length`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct metre : unit<length> {};
|
||||||
|
```
|
||||||
|
|
||||||
|
Also there are few alias templates provided as convenience helpers to simplify `Ratio` handling:
|
||||||
|
- units with prefixes
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct kilometre : kilo<metre> {};
|
||||||
|
```
|
||||||
|
|
||||||
|
- derived units
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct kilometre_per_hour : derived_unit<velocity, kilometre, hour> {};
|
||||||
|
```
|
||||||
|
|
||||||
`units::Unit` is a Concept that is satisfied by a type that is empty and publicly
|
`units::Unit` is a Concept that is satisfied by a type that is empty and publicly
|
||||||
derived from `units::unit` class template:
|
derived from `units::unit` class template:
|
||||||
|
|
||||||
@ -302,7 +321,17 @@ operation and provides it directly to `units::common_quantity_t` type trait.
|
|||||||
#### `quantity_cast`
|
#### `quantity_cast`
|
||||||
|
|
||||||
To explicitly force truncating conversions `quantity_cast` function is provided which is a direct
|
To explicitly force truncating conversions `quantity_cast` function is provided which is a direct
|
||||||
counterpart of `std::chrono::duration_cast`.
|
counterpart of `std::chrono::duration_cast`. As a template argument user can provide here either
|
||||||
|
a `quantity` type or only its template parameters (`Unit`, `Rep`):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<Quantity To, typename U, typename Rep>
|
||||||
|
requires std::same_as<typename To::dimension, typename U::dimension>
|
||||||
|
constexpr To quantity_cast(const quantity<U, Rep>& q);
|
||||||
|
|
||||||
|
template<Unit ToU, Scalar ToRep = double, typename U, typename Rep>
|
||||||
|
constexpr quantity<ToU, ToRep> quantity_cast(const quantity<U, Rep>& q);
|
||||||
|
```
|
||||||
|
|
||||||
## Strong types instead of aliases, and type downcasting capability
|
## Strong types instead of aliases, and type downcasting capability
|
||||||
|
|
||||||
@ -429,89 +458,54 @@ template<> struct downcasting_traits<downcast_from<kilometre>> : downcast_to<kil
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Adding new derived dimensions
|
## Adding custom dimensions and units
|
||||||
|
|
||||||
In order to extend the library with custom dimensions the user has to:
|
In order to extend the library with custom dimensions the user has to:
|
||||||
1. Create a new dimension type with the recipe of how to construct it from base dimensions and provide
|
1. Create a new base dimension if the predefined ones are not enough to form a new derived dimension:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
inline constexpr units::base_dimension base_dim_digital_information{"digital information"};
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create a new dimension type with the recipe of how to construct it from base dimensions and provide
|
||||||
downcasting trait for it:
|
downcasting trait for it:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
struct velocity : make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>> {};
|
struct digital_information : units::make_dimension_t<units::exp<base_dim_digital_information, 1>> {};
|
||||||
template<> struct downcasting_traits<downcast_from<velocity>> : downcast_to<velocity> {};
|
template<>
|
||||||
|
struct units::downcasting_traits<units::downcast_from<digital_information>> : units::downcast_to<digital_information> {};
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Define a concept that will match a new dimension:
|
2. Define a concept that will match a new dimension:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept Velocity = Quantity<T> && std::same_as<typename T::dimension, velocity>;
|
concept DigitalInformation = units::QuantityOf<T, digital_information>;
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Define units and provide downcasting traits for them:
|
3. Define units and provide downcasting traits for them:
|
||||||
|
|
||||||
- base unit
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
struct metre : unit<length, std::ratio<1>> {};
|
struct bit : units::unit<digital_information> {};
|
||||||
template<> struct downcasting_traits<downcast_from<metre>> : downcast_to<metre> {};
|
template<> struct units::downcasting_traits<units::downcast_from<bit>> : units::downcast_to<bit> {};
|
||||||
|
|
||||||
|
struct byte : units::unit<digital_information, units::ratio<8>> {};
|
||||||
|
template<> struct units::downcasting_traits<units::downcast_from<byte>> : units::downcast_to<byte> {};
|
||||||
```
|
```
|
||||||
|
|
||||||
- units with prefixes
|
4. Provide user-defined literals for the most important units:
|
||||||
|
|
||||||
```cpp
|
|
||||||
struct kilometre : kilo<metre> {};
|
|
||||||
template<> struct downcasting_traits<downcast_from<kilometre>> : downcast_to<kilometre> {};
|
|
||||||
```
|
|
||||||
|
|
||||||
- derived units
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
struct kilometre_per_hour : derived_unit<velocity, kilometre, hour> {};
|
|
||||||
template<> struct downcasting_traits<downcast_from<kilometre_per_hour>> : downcast_to<kilometre_per_hour> {};
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Provide user-defined literals for the most important units:
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
constexpr auto operator""_mps(unsigned long long l) { return quantity<metre_per_second, std::int64_t>(l); }
|
constexpr auto operator""_b(unsigned long long l) { return units::quantity<bit, std::int64_t>(l); }
|
||||||
constexpr auto operator""_mps(long double l) { return quantity<metre_per_second, long double>(l); }
|
constexpr auto operator""_b(long double l) { return units::quantity<bit, long double>(l); }
|
||||||
|
|
||||||
constexpr auto operator""_kmph(unsigned long long l) { return quantity<kilometre_per_hour, std::int64_t>(l); }
|
constexpr auto operator""_B(unsigned long long l) { return units::quantity<byte, std::int64_t>(l); }
|
||||||
constexpr auto operator""_kmph(long double l) { return quantity<kilometre_per_hour, long double>(l); }
|
constexpr auto operator""_B(long double l) { return units::quantity<byte, long double>(l); }
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Adding new base dimensions
|
|
||||||
|
|
||||||
For now base dimensions are defined in terms of `std::integral_constant<int, ...>` and the provided
|
|
||||||
values must be unique. For example:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
struct base_dim_length : dim_id<0> {};
|
|
||||||
struct base_dim_mass : dim_id<1> {};
|
|
||||||
struct base_dim_time : dim_id<2> {};
|
|
||||||
struct base_dim_electric_current : dim_id<3> {};
|
|
||||||
struct base_dim_temperature : dim_id<4> {};
|
|
||||||
struct base_dim_amount_of_substance : dim_id<5> {};
|
|
||||||
struct base_dim_luminous_intensity : dim_id<6> {};
|
|
||||||
```
|
|
||||||
|
|
||||||
However, as soon as C++20 class type values will be supported as non-type template parameters
|
|
||||||
base dimensions will be just a text values. For example:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
inline constexpr base_dim base_dim_length = "length";
|
|
||||||
```
|
|
||||||
|
|
||||||
With that it should be really easy to add support for any new non-standard base units to the
|
|
||||||
library without the risk of collision with any dimension type defined by the library itself or
|
|
||||||
by other users extending the library with their own dimension types.
|
|
||||||
|
|
||||||
Additionally, it should make the error logs even shorter thus easier to understand.
|
|
||||||
|
|
||||||
|
|
||||||
## Open questions
|
## Open questions
|
||||||
|
|
||||||
1. Should we ensure that dimension is always a result of `make_dimension`? How to do it?
|
1. Should we ensure that dimension is always a result of `make_dimension`? How to do it?
|
||||||
|
Reference in New Issue
Block a user