mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 18:37:15 +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`
|
`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:
|
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
|
- `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided
|
||||||
in `reference`.
|
in `reference`,
|
||||||
- `to_numerical_value(T)` static member function returning a raw value of the quantity packed in
|
- `explicit_import` static data member convertible to `bool` that specifies that the conversion
|
||||||
either `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in
|
from `T` to a `quantity` type should happen explicitly (if `true`),
|
||||||
the latter case.
|
- `explicit_export` static data member convertible to `bool` that specifies that the conversion
|
||||||
- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly`
|
from a `quantity` type to `T` should happen explicitly (if `true`),
|
||||||
or `convert_implicitly` wrapper that enables implicit conversion in the latter case.
|
- `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"
|
??? abstract "Examples"
|
||||||
|
|
||||||
@ -268,14 +268,16 @@ for which an instantiation of `quantity_like_traits` type trait yields a valid t
|
|||||||
template<>
|
template<>
|
||||||
struct mp_units::quantity_like_traits<std::chrono::seconds> {
|
struct mp_units::quantity_like_traits<std::chrono::seconds> {
|
||||||
static constexpr auto reference = si::second;
|
static constexpr auto reference = si::second;
|
||||||
|
static constexpr bool explicit_import = false;
|
||||||
|
static constexpr bool explicit_export = false;
|
||||||
using rep = std::chrono::seconds::rep;
|
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();
|
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);
|
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`
|
`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:
|
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.
|
- `reference` static data member that matches the [`Reference`](#Reference) concept.
|
||||||
- Static data member `point_origin` that matches the [`PointOrigin`](#PointOrigin) concept.
|
- `point_origin` static data member that matches the [`PointOrigin`](#PointOrigin) concept.
|
||||||
- `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided
|
- `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided
|
||||||
in `reference`.
|
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
|
- `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
|
of the point from the origin,
|
||||||
enables implicit conversion in the latter case.
|
- `from_numerical_value(rep)` static member function returning `T`.
|
||||||
- `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.
|
|
||||||
|
|
||||||
|
|
||||||
??? abstract "Examples"
|
??? abstract "Examples"
|
||||||
@ -309,17 +313,19 @@ for which an instantiation of `quantity_point_like_traits` type trait yields a v
|
|||||||
```cpp
|
```cpp
|
||||||
template<typename C>
|
template<typename C>
|
||||||
struct mp_units::quantity_point_like_traits<std::chrono::time_point<C, std::chrono::seconds>> {
|
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 auto reference = si::second;
|
||||||
static constexpr struct point_origin_ final : absolute_point_origin<isq::time> {} point_origin{};
|
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 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();
|
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));
|
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.
|
In all other scenarios, we should probably enforce explicit conversions.
|
||||||
|
|
||||||
The kinds of inter-library conversions can be easily configured in partial specializations
|
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
|
of conversion traits in the **mp-units** library. Conversion traits should provide
|
||||||
type of the conversion function should be wrapped in `convert_explicitly<T>`. Otherwise,
|
a static data member convertible to `bool`. If the value is `true`, then the conversion is
|
||||||
`convert_implicitly<T>` should be used.
|
`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
|
## 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
|
To enable such interoperability, we must define a partial specialization of
|
||||||
the `quantity_like_traits<T>` type trait. Such specialization should provide:
|
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,
|
- `rep` type that specifies the underlying storage type,
|
||||||
- `to_numerical_value(T)` static member function returning a quantity's raw value of `rep` type
|
- `explicit_import` static data member convertible to `bool` that specifies that the conversion
|
||||||
packed in either `convert_explicitly` or `convert_implicitly` wrapper.
|
from `T` to a `quantity` type should happen explicitly (if `true`),
|
||||||
- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly`
|
- `explicit_export` static data member convertible to `bool` that specifies that the conversion
|
||||||
or `convert_implicitly` wrapper.
|
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:
|
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<>
|
template<>
|
||||||
struct mp_units::quantity_like_traits<Meter> {
|
struct mp_units::quantity_like_traits<Meter> {
|
||||||
static constexpr auto reference = si::metre;
|
static constexpr auto reference = si::metre;
|
||||||
|
static constexpr bool explicit_import = false;
|
||||||
|
static constexpr bool explicit_export = true;
|
||||||
using rep = decltype(Meter::value);
|
using rep = decltype(Meter::value);
|
||||||
static constexpr convert_implicitly<rep> to_numerical_value(Meter m) { return m.value; }
|
static constexpr rep to_numerical_value(Meter m) { return m.value; }
|
||||||
static constexpr convert_explicitly<Meter> from_numerical_value(rep v) { return Meter{v}; }
|
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>`
|
we need to provide the following in the partial specialization of the `quantity_point_like_traits<T>`
|
||||||
type trait:
|
type trait:
|
||||||
|
|
||||||
- static data member `reference` that provides the quantity point reference (e.g., unit),
|
- `reference` static data member that provides the quantity point reference (e.g., unit),
|
||||||
- static data member `point_origin` that specifies the absolute point, which is the beginning of
|
- `point_origin` static data member that specifies the absolute point, which is the beginning of
|
||||||
our measurement scale for our points,
|
our measurement scale for our points,
|
||||||
- `rep` type that specifies the underlying storage type,
|
- `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
|
- `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`
|
the offset of the point from the origin,
|
||||||
wrapper.
|
- `from_numerical_value(rep)` static member function returning `T`.
|
||||||
- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly`
|
|
||||||
or `convert_implicitly` wrapper.
|
|
||||||
|
|
||||||
For example, for our `Timestamp` type, we could provide the following:
|
For example, for our `Timestamp` type, we could provide the following:
|
||||||
|
|
||||||
@ -187,9 +199,11 @@ template<>
|
|||||||
struct mp_units::quantity_point_like_traits<Timestamp> {
|
struct mp_units::quantity_point_like_traits<Timestamp> {
|
||||||
static constexpr auto reference = si::second;
|
static constexpr auto reference = si::second;
|
||||||
static constexpr auto point_origin = default_point_origin(reference);
|
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);
|
using rep = decltype(Timestamp::seconds);
|
||||||
static constexpr convert_implicitly<rep> to_numerical_value(Timestamp ts) { return ts.seconds; }
|
static constexpr rep to_numerical_value(Timestamp ts) { return ts.seconds; }
|
||||||
static constexpr convert_explicitly<Timestamp> from_numerical_value(rep v) { return Timestamp(v); }
|
static constexpr Timestamp from_numerical_value(rep v) { return Timestamp(v); }
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -149,35 +149,16 @@ struct quantity_values {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct convert_explicitly {
|
|
||||||
using value_type = T;
|
|
||||||
T value;
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
|
||||||
constexpr explicit(false) convert_explicitly(T v) noexcept(std::is_nothrow_constructible_v<T>) : value(std::move(v))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct convert_implicitly {
|
|
||||||
using value_type = T;
|
|
||||||
T value;
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
|
||||||
constexpr explicit(false) convert_implicitly(T v) noexcept(std::is_nothrow_constructible_v<T>) : value(std::move(v))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Provides support for external quantity-like types
|
* @brief Provides support for external quantity-like types
|
||||||
*
|
*
|
||||||
* The type trait should provide the @c reference object, a type alias @c rep,
|
* The type trait should provide the @c reference object, a type alias @c rep,
|
||||||
* and static member functions @c to_numerical_value(T) that returns the raw value
|
* and static member functions @c to_numerical_value(T) that returns the raw value
|
||||||
* of the quantity and @c from_numerical_value(rep) that returns @c T from @c rep.
|
* of the quantity and @c from_numerical_value(rep) that returns @c T from @c rep.
|
||||||
* Both return types should be encapsulated in either @c convert_explicitly or
|
*
|
||||||
* @c convert_implicitly to specify if the conversion is allowed to happen implicitly.
|
* If the following expression is @c true, the specified conversion will be explicit:
|
||||||
|
* - @c explicit_import for the conversion from @c T to a @c quantity type,
|
||||||
|
* - @c explicit_export for the conversion from a @c quantity type to @c T.
|
||||||
*
|
*
|
||||||
* Usage example can be found in @c mp-units/systems/si/chrono.h header file.
|
* Usage example can be found in @c mp-units/systems/si/chrono.h header file.
|
||||||
*
|
*
|
||||||
@ -193,8 +174,10 @@ struct quantity_like_traits;
|
|||||||
* a type alias @c rep, and static member functions @c to_numerical_value(T) that
|
* a type alias @c rep, and static member functions @c to_numerical_value(T) that
|
||||||
* returns the raw value of the the quantity being the offset of the point from the
|
* returns the raw value of the the quantity being the offset of the point from the
|
||||||
* origin and @c from_numerical_value(rep) that returns @c T formed this raw value.
|
* origin and @c from_numerical_value(rep) that returns @c T formed this raw value.
|
||||||
* Both return types should be encapsulated in either @c convert_explicitly or
|
*
|
||||||
* @c convert_implicitly to specify if the conversion is allowed to happen implicitly.
|
* If the following expression is @c true, the specified conversion will be explicit:
|
||||||
|
* - @c explicit_import for the conversion from @c T to a @c quantity_point type,
|
||||||
|
* - @c explicit_export for the conversion from a @c quantity_point type to @c T.
|
||||||
*
|
*
|
||||||
* Usage example can be found in @c mp-units/systems/si/chrono.h header file.
|
* Usage example can be found in @c mp-units/systems/si/chrono.h header file.
|
||||||
*
|
*
|
||||||
@ -205,14 +188,4 @@ struct quantity_point_like_traits;
|
|||||||
|
|
||||||
MP_UNITS_EXPORT_END
|
MP_UNITS_EXPORT_END
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept ConversionSpec = is_specialization_of<T, convert_explicitly> || is_specialization_of<T, convert_implicitly>;
|
|
||||||
|
|
||||||
template<typename T, typename U>
|
|
||||||
concept ConversionSpecOf = ConversionSpec<T> && std::same_as<typename T::value_type, U>;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
@ -198,12 +198,10 @@ public:
|
|||||||
|
|
||||||
template<QuantityLike Q>
|
template<QuantityLike Q>
|
||||||
requires detail::QuantityConvertibleTo<detail::quantity_like_type<Q>, quantity>
|
requires detail::QuantityConvertibleTo<detail::quantity_like_type<Q>, quantity>
|
||||||
constexpr explicit(is_specialization_of<decltype(quantity_like_traits<Q>::to_numerical_value(std::declval<Q>())),
|
constexpr explicit(quantity_like_traits<Q>::explicit_import ||
|
||||||
convert_explicitly> ||
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||||
!std::convertible_to<typename quantity_like_traits<Q>::rep, Rep>) quantity(const Q& q) :
|
!std::convertible_to<typename quantity_like_traits<Q>::rep, Rep>) quantity(const Q& q) :
|
||||||
quantity(
|
quantity(::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q), quantity_like_traits<Q>::reference})
|
||||||
::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q).value, quantity_like_traits<Q>::reference})
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,9 +307,7 @@ public:
|
|||||||
|
|
||||||
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>>
|
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>>
|
||||||
requires detail::QuantityConvertibleTo<quantity, detail::quantity_like_type<Q>>
|
requires detail::QuantityConvertibleTo<quantity, detail::quantity_like_type<Q>>
|
||||||
[[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(
|
[[nodiscard]] explicit(quantity_like_traits<Q>::explicit_export ||
|
||||||
numerical_value_is_an_implementation_detail_)),
|
|
||||||
convert_explicitly> ||
|
|
||||||
!std::convertible_to<Rep, typename quantity_like_traits<Q>::rep>) constexpr
|
!std::convertible_to<Rep, typename quantity_like_traits<Q>::rep>) constexpr
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||||
operator Q_() const
|
operator Q_() const
|
||||||
@ -319,8 +315,7 @@ public:
|
|||||||
std::is_nothrow_copy_constructible_v<rep>)
|
std::is_nothrow_copy_constructible_v<rep>)
|
||||||
{
|
{
|
||||||
return quantity_like_traits<Q>::from_numerical_value(
|
return quantity_like_traits<Q>::from_numerical_value(
|
||||||
numerical_value_in(get_unit(quantity_like_traits<Q>::reference)))
|
numerical_value_in(get_unit(quantity_like_traits<Q>::reference)));
|
||||||
.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// member unary operators
|
// member unary operators
|
||||||
@ -648,8 +643,7 @@ template<Representation Value>
|
|||||||
explicit(false) quantity(Value) -> quantity<one, Value>;
|
explicit(false) quantity(Value) -> quantity<one, Value>;
|
||||||
|
|
||||||
template<QuantityLike Q>
|
template<QuantityLike Q>
|
||||||
explicit(
|
explicit(quantity_like_traits<Q>::explicit_import)
|
||||||
is_specialization_of<decltype(quantity_like_traits<Q>::to_numerical_value(std::declval<Q>())), convert_explicitly>)
|
|
||||||
quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
||||||
|
|
||||||
MP_UNITS_EXPORT_END
|
MP_UNITS_EXPORT_END
|
||||||
|
@ -45,23 +45,33 @@ constexpr bool is_derived_from_specialization_of_quantity =
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
MP_UNITS_EXPORT_BEGIN
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all quantities in the library
|
* @brief A concept matching all quantities in the library
|
||||||
*
|
*
|
||||||
* Satisfied by all types being a either specialization or derived from `quantity`
|
* Satisfied by all types being a either specialization or derived from `quantity`
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
MP_UNITS_EXPORT template<typename T>
|
||||||
concept Quantity = detail::is_derived_from_specialization_of_quantity<T>;
|
concept Quantity = detail::is_derived_from_specialization_of_quantity<T>;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T, template<typename> typename Traits>
|
||||||
|
concept QuantityLikeImpl = requires(const T& qty, const Traits<T>::rep& num) {
|
||||||
|
{ Traits<T>::to_numerical_value(qty) } -> std::same_as<typename Traits<T>::rep>;
|
||||||
|
{ Traits<T>::from_numerical_value(num) } -> std::same_as<T>;
|
||||||
|
{ Traits<T>::explicit_import } -> std::convertible_to<bool>;
|
||||||
|
{ Traits<T>::explicit_export } -> std::convertible_to<bool>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all quantities with provided quantity spec
|
* @brief A concept matching all quantities with provided quantity spec
|
||||||
*
|
*
|
||||||
* Satisfied by all quantities with a quantity_spec being the instantiation derived from
|
* Satisfied by all quantities with a quantity_spec being the instantiation derived from
|
||||||
* the provided quantity_spec type.
|
* the provided quantity_spec type.
|
||||||
*/
|
*/
|
||||||
template<typename Q, auto QS>
|
MP_UNITS_EXPORT template<typename Q, auto QS>
|
||||||
concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(Q::quantity_spec)>, QS>;
|
concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(Q::quantity_spec)>, QS>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,18 +80,9 @@ concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(
|
|||||||
* Satisfied by all external types (not-defined in mp-units) that via a `quantity_like_traits` provide
|
* Satisfied by all external types (not-defined in mp-units) that via a `quantity_like_traits` provide
|
||||||
* all quantity-specific information.
|
* all quantity-specific information.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
MP_UNITS_EXPORT template<typename T>
|
||||||
concept QuantityLike = requires {
|
concept QuantityLike = !Quantity<T> && detail::QuantityLikeImpl<T, quantity_like_traits> && requires {
|
||||||
quantity_like_traits<T>::reference;
|
typename quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>;
|
||||||
requires Reference<std::remove_const_t<decltype(quantity_like_traits<T>::reference)>>;
|
|
||||||
typename quantity_like_traits<T>::rep;
|
|
||||||
requires RepresentationOf<typename quantity_like_traits<T>::rep,
|
|
||||||
get_quantity_spec(quantity_like_traits<T>::reference).character>;
|
|
||||||
} && requires(T q, typename quantity_like_traits<T>::rep v) {
|
|
||||||
{ quantity_like_traits<T>::to_numerical_value(q) } -> detail::ConversionSpecOf<typename quantity_like_traits<T>::rep>;
|
|
||||||
{ quantity_like_traits<T>::from_numerical_value(v) } -> detail::ConversionSpecOf<T>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MP_UNITS_EXPORT_END
|
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
@ -248,13 +248,12 @@ public:
|
|||||||
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>,
|
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>,
|
||||||
quantity_type>
|
quantity_type>
|
||||||
constexpr explicit(
|
constexpr explicit(
|
||||||
is_specialization_of<decltype(quantity_point_like_traits<QP>::to_numerical_value(std::declval<QP>())),
|
quantity_point_like_traits<QP>::explicit_import ||
|
||||||
convert_explicitly> ||
|
|
||||||
!std::convertible_to<
|
!std::convertible_to<
|
||||||
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>, quantity_type>)
|
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>, quantity_type>)
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||||
quantity_point(const QP& qp) :
|
quantity_point(const QP& qp) :
|
||||||
quantity_from_origin_is_an_implementation_detail_(quantity_point_like_traits<QP>::to_numerical_value(qp).value,
|
quantity_from_origin_is_an_implementation_detail_(quantity_point_like_traits<QP>::to_numerical_value(qp),
|
||||||
get_unit(quantity_point_like_traits<QP>::reference))
|
get_unit(quantity_point_like_traits<QP>::reference))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -371,10 +370,7 @@ public:
|
|||||||
std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||||
typename quantity_point_like_traits<QP>::rep>>
|
typename quantity_point_like_traits<QP>::rep>>
|
||||||
[[nodiscard]] explicit(
|
[[nodiscard]] explicit(
|
||||||
is_specialization_of<
|
quantity_point_like_traits<QP>::explicit_export ||
|
||||||
decltype(quantity_point_like_traits<QP>::from_numerical_value(
|
|
||||||
quantity_from_origin_is_an_implementation_detail_.numerical_value_is_an_implementation_detail_)),
|
|
||||||
convert_explicitly> ||
|
|
||||||
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||||
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||||
@ -384,8 +380,7 @@ public:
|
|||||||
std::is_nothrow_copy_constructible_v<rep>)
|
std::is_nothrow_copy_constructible_v<rep>)
|
||||||
{
|
{
|
||||||
return quantity_point_like_traits<QP>::from_numerical_value(
|
return quantity_point_like_traits<QP>::from_numerical_value(
|
||||||
quantity_from_origin_is_an_implementation_detail_.numerical_value_is_an_implementation_detail_)
|
quantity_from_origin_is_an_implementation_detail_.numerical_value_is_an_implementation_detail_);
|
||||||
.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename QP_, QuantityPointLike QP = std::remove_cvref_t<QP_>>
|
template<typename QP_, QuantityPointLike QP = std::remove_cvref_t<QP_>>
|
||||||
@ -393,10 +388,7 @@ public:
|
|||||||
std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||||
typename quantity_point_like_traits<QP>::rep>>
|
typename quantity_point_like_traits<QP>::rep>>
|
||||||
[[nodiscard]] explicit(
|
[[nodiscard]] explicit(
|
||||||
is_specialization_of<
|
quantity_point_like_traits<QP>::explicit_export ||
|
||||||
decltype(quantity_point_like_traits<QP>::from_numerical_value(
|
|
||||||
quantity_from_origin_is_an_implementation_detail_.numerical_value_is_an_implementation_detail_)),
|
|
||||||
convert_explicitly> ||
|
|
||||||
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||||
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||||
@ -406,8 +398,7 @@ public:
|
|||||||
std::is_nothrow_move_constructible_v<rep>)
|
std::is_nothrow_move_constructible_v<rep>)
|
||||||
{
|
{
|
||||||
return quantity_point_like_traits<QP>::from_numerical_value(
|
return quantity_point_like_traits<QP>::from_numerical_value(
|
||||||
std::move(quantity_from_origin_is_an_implementation_detail_).numerical_value_is_an_implementation_detail_)
|
std::move(quantity_from_origin_is_an_implementation_detail_).numerical_value_is_an_implementation_detail_);
|
||||||
.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// member unary operators
|
// member unary operators
|
||||||
@ -561,8 +552,7 @@ template<Quantity Q, PointOriginFor<Q::quantity_spec> PO>
|
|||||||
quantity_point(Q q, PO) -> quantity_point<Q::reference, PO{}, typename Q::rep>;
|
quantity_point(Q q, PO) -> quantity_point<Q::reference, PO{}, typename Q::rep>;
|
||||||
|
|
||||||
template<QuantityPointLike QP>
|
template<QuantityPointLike QP>
|
||||||
explicit(is_specialization_of<decltype(quantity_point_like_traits<QP>::to_numerical_value(std::declval<QP>())),
|
explicit(quantity_point_like_traits<QP>::explicit_import) quantity_point(QP)
|
||||||
convert_explicitly>) quantity_point(QP)
|
|
||||||
-> quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
|
-> quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
|
||||||
typename quantity_point_like_traits<QP>::rep>;
|
typename quantity_point_like_traits<QP>::rep>;
|
||||||
|
|
||||||
|
@ -135,19 +135,9 @@ concept QuantityPointOf =
|
|||||||
* all quantity_point-specific information.
|
* all quantity_point-specific information.
|
||||||
*/
|
*/
|
||||||
MP_UNITS_EXPORT template<typename T>
|
MP_UNITS_EXPORT template<typename T>
|
||||||
concept QuantityPointLike = requires {
|
concept QuantityPointLike = !QuantityPoint<T> && detail::QuantityLikeImpl<T, quantity_point_like_traits> && requires {
|
||||||
quantity_point_like_traits<T>::reference;
|
typename quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin,
|
||||||
requires Reference<std::remove_const_t<decltype(quantity_point_like_traits<T>::reference)>>;
|
typename quantity_point_like_traits<T>::rep>;
|
||||||
quantity_point_like_traits<T>::point_origin;
|
|
||||||
requires PointOrigin<std::remove_const_t<decltype(quantity_point_like_traits<T>::point_origin)>>;
|
|
||||||
typename quantity_point_like_traits<T>::rep;
|
|
||||||
requires RepresentationOf<typename quantity_point_like_traits<T>::rep,
|
|
||||||
get_quantity_spec(quantity_point_like_traits<T>::reference).character>;
|
|
||||||
} && requires(T qp, typename quantity_point_like_traits<T>::rep v) {
|
|
||||||
{
|
|
||||||
quantity_point_like_traits<T>::to_numerical_value(qp)
|
|
||||||
} -> detail::ConversionSpecOf<typename quantity_point_like_traits<T>::rep>;
|
|
||||||
{ quantity_point_like_traits<T>::from_numerical_value(v) } -> detail::ConversionSpecOf<T>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
@ -73,18 +73,21 @@ template<typename Period>
|
|||||||
MP_UNITS_EXPORT template<typename Rep, typename Period>
|
MP_UNITS_EXPORT template<typename Rep, typename Period>
|
||||||
struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
|
struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
|
||||||
static constexpr auto reference = detail::time_unit_from_chrono_period<Period>();
|
static constexpr auto reference = detail::time_unit_from_chrono_period<Period>();
|
||||||
|
static constexpr bool explicit_import = false;
|
||||||
|
static constexpr bool explicit_export = false;
|
||||||
using rep = Rep;
|
using rep = Rep;
|
||||||
|
using T = std::chrono::duration<Rep, Period>;
|
||||||
|
|
||||||
[[nodiscard]] static constexpr convert_implicitly<rep> to_numerical_value(
|
[[nodiscard]] static constexpr rep to_numerical_value(const T& q) noexcept(
|
||||||
const std::chrono::duration<Rep, Period>& q) noexcept(std::is_nothrow_copy_constructible_v<rep>)
|
std::is_nothrow_copy_constructible_v<rep>)
|
||||||
{
|
{
|
||||||
return q.count();
|
return q.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static constexpr convert_implicitly<std::chrono::duration<Rep, Period>> from_numerical_value(
|
[[nodiscard]] static constexpr T from_numerical_value(const rep& v) noexcept(
|
||||||
const rep& v) noexcept(std::is_nothrow_copy_constructible_v<rep>)
|
std::is_nothrow_copy_constructible_v<rep>)
|
||||||
{
|
{
|
||||||
return std::chrono::duration<Rep, Period>(v);
|
return T(v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,18 +102,19 @@ MP_UNITS_EXPORT_BEGIN
|
|||||||
|
|
||||||
template<typename C, typename Rep, typename Period>
|
template<typename C, typename Rep, typename Period>
|
||||||
struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> {
|
struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> {
|
||||||
using T = std::chrono::time_point<C, std::chrono::duration<Rep, Period>>;
|
|
||||||
static constexpr auto reference = detail::time_unit_from_chrono_period<Period>();
|
static constexpr auto reference = detail::time_unit_from_chrono_period<Period>();
|
||||||
static constexpr auto point_origin = chrono_point_origin<C>;
|
static constexpr auto point_origin = chrono_point_origin<C>;
|
||||||
|
static constexpr bool explicit_import = false;
|
||||||
|
static constexpr bool explicit_export = false;
|
||||||
using rep = Rep;
|
using rep = Rep;
|
||||||
|
using T = std::chrono::time_point<C, std::chrono::duration<Rep, Period>>;
|
||||||
|
|
||||||
[[nodiscard]] static constexpr convert_implicitly<rep> to_numerical_value(const T& tp) noexcept(
|
[[nodiscard]] static constexpr rep to_numerical_value(const T& tp) noexcept(std::is_nothrow_copy_constructible_v<rep>)
|
||||||
std::is_nothrow_copy_constructible_v<rep>)
|
|
||||||
{
|
{
|
||||||
return tp.time_since_epoch().count();
|
return tp.time_since_epoch().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static constexpr convert_implicitly<T> from_numerical_value(const rep& v) noexcept(
|
[[nodiscard]] static constexpr T from_numerical_value(const rep& v) noexcept(
|
||||||
std::is_nothrow_copy_constructible_v<rep>)
|
std::is_nothrow_copy_constructible_v<rep>)
|
||||||
{
|
{
|
||||||
return T(std::chrono::duration<Rep, Period>(v));
|
return T(std::chrono::duration<Rep, Period>(v));
|
||||||
|
Reference in New Issue
Block a user