From d20fa9c9efa43cca39547aba494421257715769f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 16 Nov 2019 19:56:03 +0100 Subject: [PATCH] "Adding custom representations" chapter added to DESIGN --- doc/DESIGN.md | 84 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/doc/DESIGN.md b/doc/DESIGN.md index df07db83..9c3a1db9 100644 --- a/doc/DESIGN.md +++ b/doc/DESIGN.md @@ -413,24 +413,6 @@ template class quantity; ``` -where `Scalar` is the following concept: - -```cpp -template -concept basic-arithmetic = // exposition only - std::magma && - std::magma && - std::magma && - std::magma; - -template -concept Scalar = - (!Quantity) && - std::regular && - std::totally_ordered && - basic-arithmetic; -``` - `units::Quantity` is a concept that is satisfied by a type that is an instantiation of `units::quantity` class template: @@ -860,3 +842,69 @@ In order to extend the library with custom dimensions the user has to: constexpr auto operator""_B(long double l) { return units::quantity(l); } } ``` + +## Adding custom representations + +In theory `quantity` can take any arithmetic-like type as a `Rep` template parameter. In +practice some interface is forced by numeric concepts. + +To provide basic library functionality the type should satisfy the following concept: + +```cpp +template +concept basic-arithmetic = // exposition only + std::magma && + std::magma && + std::magma && + std::magma; + +template +concept Scalar = + (!Quantity) && + std::regular && + std::totally_ordered && + basic-arithmetic; +``` + +The above implies that the `Rep` type should provide at least: +- default constructor, destructor, copy-constructor, and copy-assignment operator +- `operator==(Rep, Rep)`, `operator!=(Rep, Rep)` +- `operator<(Rep, Rep)`, `operator>(Rep, Rep)`, `operator<=(Rep, Rep)`, `operator>=(Rep, Rep)` +- `operator-(Rep)` +- `operator+(Rep, Rep)`, `operator-(Rep, Rep)`, `operator*(Rep, Rep)`, `operator*(Rep, Rep)` + +Above also requires that the `Rep` should be implicitly convertible from integral types (i.e. `int`) so a proper implicit converting constructor should be provided. + +Moreover, in most cases to observe expected behavior `Rep` will have to be registered as a +floating-point representation type by specializing `units::treat_as_floating_point` type +trait: + +```cpp +template +inline constexpr bool treat_as_floating_point; +``` + +An example of such a type can be found in [measurement example](../example/measurement.cpp). + +However, as written above this will enable only a basic functionality of the library. In case +additional `quantity` operations are needed the user may opt-in to any of them by providing +the equivalent operation for `Rep` type. Here is an additional list of opt-in operations: +- `operator++()` +- `operator++(int)` +- `operator--()` +- `operator--(int)` +- `operator+=(Rep)` +- `operator-=(Rep)` +- `operator*=(Rep)` +- `operator/=(Rep)` +- `operator%=(Rep)` +- `operator%=(Rep)` +- `operator%(Rep, Rep)` + +`quantity` also has 4 static functions `zero()`, `one()`, `min()`, and `max()` which can +be enabled by providing a specialization of `quantity_values` type trait for `Rep` type: + +```cpp +template +struct quantity_values; +```