mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-01 03:14:29 +02:00
refactor: 💥 convertibility traits and concepts refactored to use bool
flags instead of wrappers
This commit is contained in:
@@ -250,15 +250,15 @@ class template.
|
||||
`QuantityLike` concept provides interoperability with other libraries and is satisfied by a type `T`
|
||||
for which an instantiation of `quantity_like_traits` type trait yields a valid type that provides:
|
||||
|
||||
- Static data member `reference` that matches the [`Reference`](#Reference) concept,
|
||||
- `reference` static data member that matches the [`Reference`](#Reference) concept,
|
||||
- `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided
|
||||
in `reference`.
|
||||
- `to_numerical_value(T)` static member function returning a raw value of the quantity packed in
|
||||
either `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in
|
||||
the latter case.
|
||||
- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly`
|
||||
or `convert_implicitly` wrapper that enables implicit conversion in the latter case.
|
||||
|
||||
in `reference`,
|
||||
- `explicit_import` static data member convertible to `bool` that specifies that the conversion
|
||||
from `T` to a `quantity` type should happen explicitly (if `true`),
|
||||
- `explicit_export` static data member convertible to `bool` that specifies that the conversion
|
||||
from a `quantity` type to `T` should happen explicitly (if `true`),
|
||||
- `to_numerical_value(T)` static member function returning a raw value of the quantity,
|
||||
- `from_numerical_value(rep)` static member function returning `T`.
|
||||
|
||||
??? abstract "Examples"
|
||||
|
||||
@@ -268,14 +268,16 @@ for which an instantiation of `quantity_like_traits` type trait yields a valid t
|
||||
template<>
|
||||
struct mp_units::quantity_like_traits<std::chrono::seconds> {
|
||||
static constexpr auto reference = si::second;
|
||||
static constexpr bool explicit_import = false;
|
||||
static constexpr bool explicit_export = false;
|
||||
using rep = std::chrono::seconds::rep;
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<rep> to_numerical_value(const std::chrono::seconds& d)
|
||||
[[nodiscard]] static constexpr rep to_numerical_value(const std::chrono::seconds& d)
|
||||
{
|
||||
return d.count();
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<std::chrono::seconds> from_numerical_value(const rep& v)
|
||||
[[nodiscard]] static constexpr std::chrono::seconds from_numerical_value(const rep& v)
|
||||
{
|
||||
return std::chrono::seconds(v);
|
||||
}
|
||||
@@ -291,15 +293,17 @@ for which an instantiation of `quantity_like_traits` type trait yields a valid t
|
||||
`QuantityPointLike` concept provides interoperability with other libraries and is satisfied by a type `T`
|
||||
for which an instantiation of `quantity_point_like_traits` type trait yields a valid type that provides:
|
||||
|
||||
- Static data member `reference` that matches the [`Reference`](#Reference) concept.
|
||||
- Static data member `point_origin` that matches the [`PointOrigin`](#PointOrigin) concept.
|
||||
- `reference` static data member that matches the [`Reference`](#Reference) concept.
|
||||
- `point_origin` static data member that matches the [`PointOrigin`](#PointOrigin) concept.
|
||||
- `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided
|
||||
in `reference`.
|
||||
- `explicit_import` static data member convertible to `bool` that specifies that the conversion
|
||||
from `T` to a `quantity_point` type should happen explicitly (if `true`),
|
||||
- `explicit_export` static data member convertible to `bool` that specifies that the conversion
|
||||
from a `quantity_point` type to `T` should happen explicitly (if `true`),
|
||||
- `to_numerical_value(T)` static member function returning a raw value of the quantity being the offset
|
||||
of the point from the origin packed in either `convert_explicitly` or `convert_implicitly` wrapper that
|
||||
enables implicit conversion in the latter case.
|
||||
- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly`
|
||||
or `convert_implicitly` wrapper that enables implicit conversion in the latter case.
|
||||
of the point from the origin,
|
||||
- `from_numerical_value(rep)` static member function returning `T`.
|
||||
|
||||
|
||||
??? abstract "Examples"
|
||||
@@ -309,17 +313,19 @@ for which an instantiation of `quantity_point_like_traits` type trait yields a v
|
||||
```cpp
|
||||
template<typename C>
|
||||
struct mp_units::quantity_point_like_traits<std::chrono::time_point<C, std::chrono::seconds>> {
|
||||
using T = std::chrono::time_point<C, std::chrono::seconds>;
|
||||
static constexpr auto reference = si::second;
|
||||
static constexpr struct point_origin_ final : absolute_point_origin<isq::time> {} point_origin{};
|
||||
static constexpr bool explicit_import = false;
|
||||
static constexpr bool explicit_export = false;
|
||||
using rep = std::chrono::seconds::rep;
|
||||
using T = std::chrono::time_point<C, std::chrono::seconds>;
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<rep> to_numerical_value(const T& tp)
|
||||
[[nodiscard]] static constexpr rep to_numerical_value(const T& tp)
|
||||
{
|
||||
return tp.time_since_epoch().count();
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<T> from_numerical_value(const rep& v)
|
||||
[[nodiscard]] static constexpr T from_numerical_value(const rep& v)
|
||||
{
|
||||
return T(std::chrono::seconds(v));
|
||||
}
|
||||
|
@@ -31,9 +31,15 @@ Typically, the implicit conversions are allowed in cases where:
|
||||
In all other scenarios, we should probably enforce explicit conversions.
|
||||
|
||||
The kinds of inter-library conversions can be easily configured in partial specializations
|
||||
of conversion traits in the **mp-units** library. To require an explicit conversion, the return
|
||||
type of the conversion function should be wrapped in `convert_explicitly<T>`. Otherwise,
|
||||
`convert_implicitly<T>` should be used.
|
||||
of conversion traits in the **mp-units** library. Conversion traits should provide
|
||||
a static data member convertible to `bool`. If the value is `true`, then the conversion is
|
||||
`explicit`. Otherwise, if the value is `false`, implicit conversions will be allowed.
|
||||
The names of the flags are as follows:
|
||||
|
||||
- `explicit_import` to describe conversion from the external entity to the one in this
|
||||
library (import case),
|
||||
- `explicit_export` to describe conversion from the entity in this library to the external one
|
||||
(export case).
|
||||
|
||||
|
||||
## Quantities conversions
|
||||
@@ -56,12 +62,14 @@ to see the opposite conversions stated explicitly in our code.
|
||||
To enable such interoperability, we must define a partial specialization of
|
||||
the `quantity_like_traits<T>` type trait. Such specialization should provide:
|
||||
|
||||
- static data member `reference` that provides the quantity reference (e.g., unit),
|
||||
- `reference` static data member that provides the quantity reference (e.g., unit),
|
||||
- `rep` type that specifies the underlying storage type,
|
||||
- `to_numerical_value(T)` static member function returning a quantity's raw value of `rep` type
|
||||
packed in either `convert_explicitly` or `convert_implicitly` wrapper.
|
||||
- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly`
|
||||
or `convert_implicitly` wrapper.
|
||||
- `explicit_import` static data member convertible to `bool` that specifies that the conversion
|
||||
from `T` to a `quantity` type should happen explicitly (if `true`),
|
||||
- `explicit_export` static data member convertible to `bool` that specifies that the conversion
|
||||
from a `quantity` type to `T` should happen explicitly (if `true`),
|
||||
- `to_numerical_value(T)` static member function returning a quantity's raw value of `rep` type,
|
||||
- `from_numerical_value(rep)` static member function returning `T`.
|
||||
|
||||
For example, for our `Meter` type, we could provide the following:
|
||||
|
||||
@@ -69,9 +77,11 @@ For example, for our `Meter` type, we could provide the following:
|
||||
template<>
|
||||
struct mp_units::quantity_like_traits<Meter> {
|
||||
static constexpr auto reference = si::metre;
|
||||
static constexpr bool explicit_import = false;
|
||||
static constexpr bool explicit_export = true;
|
||||
using rep = decltype(Meter::value);
|
||||
static constexpr convert_implicitly<rep> to_numerical_value(Meter m) { return m.value; }
|
||||
static constexpr convert_explicitly<Meter> from_numerical_value(rep v) { return Meter{v}; }
|
||||
static constexpr rep to_numerical_value(Meter m) { return m.value; }
|
||||
static constexpr Meter from_numerical_value(rep v) { return Meter{v}; }
|
||||
};
|
||||
```
|
||||
|
||||
@@ -170,15 +180,17 @@ To allow the conversion between our custom `Timestamp` type and the `quantity_po
|
||||
we need to provide the following in the partial specialization of the `quantity_point_like_traits<T>`
|
||||
type trait:
|
||||
|
||||
- static data member `reference` that provides the quantity point reference (e.g., unit),
|
||||
- static data member `point_origin` that specifies the absolute point, which is the beginning of
|
||||
- `reference` static data member that provides the quantity point reference (e.g., unit),
|
||||
- `point_origin` static data member that specifies the absolute point, which is the beginning of
|
||||
our measurement scale for our points,
|
||||
- `rep` type that specifies the underlying storage type,
|
||||
- `explicit_import` static data member convertible to `bool` that specifies that the conversion
|
||||
from `T` to a `quantity` type should happen explicitly (if `true`),
|
||||
- `explicit_export` static data member convertible to `bool` that specifies that the conversion
|
||||
from a `quantity` type to `T` should happen explicitly (if `true`),
|
||||
- `to_numerical_value(T)` static member function returning a raw value of the `quantity` being
|
||||
the offset of the point from the origin packed in either `convert_explicitly` or `convert_implicitly`
|
||||
wrapper.
|
||||
- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly`
|
||||
or `convert_implicitly` wrapper.
|
||||
the offset of the point from the origin,
|
||||
- `from_numerical_value(rep)` static member function returning `T`.
|
||||
|
||||
For example, for our `Timestamp` type, we could provide the following:
|
||||
|
||||
@@ -187,9 +199,11 @@ template<>
|
||||
struct mp_units::quantity_point_like_traits<Timestamp> {
|
||||
static constexpr auto reference = si::second;
|
||||
static constexpr auto point_origin = default_point_origin(reference);
|
||||
static constexpr bool explicit_import = false;
|
||||
static constexpr bool explicit_export = true;
|
||||
using rep = decltype(Timestamp::seconds);
|
||||
static constexpr convert_implicitly<rep> to_numerical_value(Timestamp ts) { return ts.seconds; }
|
||||
static constexpr convert_explicitly<Timestamp> from_numerical_value(rep v) { return Timestamp(v); }
|
||||
static constexpr rep to_numerical_value(Timestamp ts) { return ts.seconds; }
|
||||
static constexpr Timestamp from_numerical_value(rep v) { return Timestamp(v); }
|
||||
};
|
||||
```
|
||||
|
||||
|
Reference in New Issue
Block a user