feat: interoperability with other libraries redesigned

This commit is contained in:
Mateusz Pusz
2023-09-30 22:23:18 -06:00
parent 335ebc9b7b
commit 5a74cd66ba
9 changed files with 182 additions and 47 deletions
@@ -74,15 +74,19 @@ concept QuantityOf = Quantity<Q> && ReferenceOf<std::remove_const_t<decltype(Q::
* all quantity-specific information.
*/
template<typename T>
concept QuantityLike = requires(T q) {
concept QuantityLike = requires {
quantity_like_traits<T>::reference;
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) {
{
make_quantity<quantity_like_traits<T>::reference>(quantity_like_traits<T>::value(q))
} -> std::same_as<quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>>;
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>;
};
} // namespace mp_units
@@ -173,7 +173,7 @@ concept QuantityPointOf =
* all quantity_point-specific information.
*/
template<typename T>
concept QuantityPointLike = requires(T qp) {
concept QuantityPointLike = requires {
quantity_point_like_traits<T>::reference;
requires Reference<std::remove_const_t<decltype(quantity_point_like_traits<T>::reference)>>;
quantity_point_like_traits<T>::point_origin;
@@ -181,13 +181,15 @@ concept QuantityPointLike = requires(T qp) {
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 Quantity<std::remove_cvref_t<decltype(quantity_point_like_traits<T>::quantity_from_origin(qp))>>;
} && requires(T qp, quantity<quantity_point_like_traits<T>::reference, typename quantity_point_like_traits<T>::rep> q) {
{
make_quantity_point<quantity_point_like_traits<T>::point_origin>(
quantity_point_like_traits<T>::quantity_from_origin(qp))
}
-> std::same_as<quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin,
typename quantity_point_like_traits<T>::rep>>;
quantity_point_like_traits<T>::to_quantity(qp)
} -> detail::ConversionSpecOf<
quantity<quantity_point_like_traits<T>::reference, typename quantity_point_like_traits<T>::rep>>;
{
quantity_point_like_traits<T>::from_quantity(q)
} -> detail::ConversionSpecOf<T>;
};
} // namespace mp_units
@@ -132,11 +132,42 @@ struct quantity_values {
}
};
template<typename T>
struct convert_explicitly {
using value_type = T;
T value;
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;
constexpr explicit(false) convert_implicitly(T v) noexcept(std::is_nothrow_constructible_v<T>) : value(std::move(v))
{
}
};
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
/**
* @brief Provides support for external quantity-like types
*
* The type trait should provide the @c reference object, a type alias @c rep,
* and a static member function @c value(T) that returns the raw value of the quantity.
* 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.
* 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.
*
* Usage example can be found in @c units/chrono.h header file.
*
@@ -149,8 +180,11 @@ struct quantity_like_traits;
* @brief Provides support for external quantity point-like types
*
* The type trait should provide nested @c reference and @c origin objects,
* a type alias @c rep, and a static member function @c quantity_from_origin(T) that will
* return the quantity being the offset of the point from the origin.
* a type alias @c rep, and static member functions @c to_quantity(T) that returns
* the quantity being the offset of the point from the origin and
* @c from_quantity(quantity<reference, rep>) that returns @c T form this quantity.
* 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.
*
* Usage example can be found in @c units/chrono.h header file.
*
+26 -3
View File
@@ -133,8 +133,10 @@ public:
template<QuantityLike Q>
requires detail::QuantityConvertibleTo<
quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>, quantity>
constexpr explicit quantity(const Q& q) :
quantity(make_quantity<quantity_like_traits<Q>::reference>(quantity_like_traits<Q>::value(q)))
constexpr explicit(
is_specialization_of<decltype(quantity_like_traits<Q>::to_numerical_value(std::declval<Q>())), convert_explicitly>)
quantity(const Q& q) :
quantity(make_quantity<quantity_like_traits<Q>::reference>(quantity_like_traits<Q>::to_numerical_value(q).value))
{
}
@@ -189,6 +191,25 @@ public:
return (*this).force_in(U{}).numerical_value_;
}
// conversion operators
template<QuantityLike Q>
[[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(numerical_value_)),
convert_explicitly>) constexpr
operator Q() const& noexcept(noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_)) &&
std::is_nothrow_copy_constructible_v<rep>)
{
return quantity_like_traits<Q>::from_numerical_value(numerical_value_).value;
}
template<QuantityLike Q>
[[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(numerical_value_)),
convert_explicitly>) constexpr
operator Q() const&& noexcept(noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_)) &&
std::is_nothrow_copy_constructible_v<rep>)
{
return quantity_like_traits<Q>::from_numerical_value(std::move(numerical_value_)).value;
}
// member unary operators
[[nodiscard]] constexpr Quantity auto operator+() const
requires requires(rep v) {
@@ -365,7 +386,9 @@ private:
// CTAD
template<QuantityLike Q>
explicit quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
explicit(
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>;
// binary operators on quantities
template<auto R1, typename Rep1, auto R2, typename Rep2>
+30 -5
View File
@@ -128,8 +128,10 @@ public:
std::convertible_to<
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>,
quantity_type>
constexpr explicit quantity_point(const QP& qp) :
quantity_from_origin_(quantity_point_like_traits<QP>::quantity_from_origin(qp))
constexpr explicit(
is_specialization_of<decltype(quantity_point_like_traits<QP>::to_quantity(std::declval<QP>())), convert_explicitly>)
quantity_point(const QP& qp) :
quantity_from_origin_(quantity_point_like_traits<QP>::to_quantity(qp).value)
{
}
@@ -182,6 +184,27 @@ public:
return make_quantity_point<PO>(quantity_ref_from(PO).force_in(U{}));
}
// conversion operators
template<QuantityPointLike QP>
[[nodiscard]] explicit(
is_specialization_of<decltype(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_)),
convert_explicitly>) constexpr
operator QP() const& noexcept(noexcept(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_)) &&
std::is_nothrow_copy_constructible_v<rep>)
{
return quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_).value;
}
template<QuantityPointLike QP>
[[nodiscard]] explicit(
is_specialization_of<decltype(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_)),
convert_explicitly>) constexpr
operator QP() const&& noexcept(noexcept(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_)) &&
std::is_nothrow_copy_constructible_v<rep>)
{
return quantity_point_like_traits<QP>::from_quantity(std::move(quantity_from_origin_)).value;
}
// member unary operators
template<typename QP>
friend constexpr decltype(auto) operator++(QP&& qp)
@@ -249,9 +272,11 @@ private:
// CTAD
template<QuantityPointLike QP>
explicit quantity_point(QP)
-> quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
typename quantity_point_like_traits<QP>::rep>;
explicit(
is_specialization_of<decltype(quantity_point_like_traits<QP>::to_quantity(std::declval<QP>())), convert_explicitly>)
quantity_point(QP)
-> quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
typename quantity_point_like_traits<QP>::rep>;
template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
// TODO simplify when gcc catches up