forked from mpusz/mp-units
refactor: 💥 convertibility traits and concepts refactored to use bool flags instead of wrappers
This commit is contained in:
@@ -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
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
@@ -193,8 +174,10 @@ struct quantity_like_traits;
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
@@ -205,14 +188,4 @@ struct quantity_point_like_traits;
|
||||
|
||||
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
|
||||
|
||||
@@ -198,12 +198,10 @@ public:
|
||||
|
||||
template<QuantityLike Q>
|
||||
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>())),
|
||||
convert_explicitly> ||
|
||||
constexpr explicit(quantity_like_traits<Q>::explicit_import ||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
!std::convertible_to<typename quantity_like_traits<Q>::rep, Rep>) quantity(const Q& q) :
|
||||
quantity(
|
||||
::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q).value, quantity_like_traits<Q>::reference})
|
||||
quantity(::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q), quantity_like_traits<Q>::reference})
|
||||
{
|
||||
}
|
||||
|
||||
@@ -309,9 +307,7 @@ public:
|
||||
|
||||
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>>
|
||||
requires detail::QuantityConvertibleTo<quantity, detail::quantity_like_type<Q>>
|
||||
[[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(
|
||||
numerical_value_is_an_implementation_detail_)),
|
||||
convert_explicitly> ||
|
||||
[[nodiscard]] explicit(quantity_like_traits<Q>::explicit_export ||
|
||||
!std::convertible_to<Rep, typename quantity_like_traits<Q>::rep>) constexpr
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
operator Q_() const
|
||||
@@ -319,8 +315,7 @@ public:
|
||||
std::is_nothrow_copy_constructible_v<rep>)
|
||||
{
|
||||
return quantity_like_traits<Q>::from_numerical_value(
|
||||
numerical_value_in(get_unit(quantity_like_traits<Q>::reference)))
|
||||
.value;
|
||||
numerical_value_in(get_unit(quantity_like_traits<Q>::reference)));
|
||||
}
|
||||
|
||||
// member unary operators
|
||||
@@ -648,8 +643,7 @@ template<Representation Value>
|
||||
explicit(false) quantity(Value) -> quantity<one, Value>;
|
||||
|
||||
template<QuantityLike Q>
|
||||
explicit(
|
||||
is_specialization_of<decltype(quantity_like_traits<Q>::to_numerical_value(std::declval<Q>())), convert_explicitly>)
|
||||
explicit(quantity_like_traits<Q>::explicit_import)
|
||||
quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
@@ -45,23 +45,33 @@ constexpr bool is_derived_from_specialization_of_quantity =
|
||||
|
||||
} // namespace detail
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantities in the library
|
||||
*
|
||||
* 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>;
|
||||
|
||||
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
|
||||
*
|
||||
* Satisfied by all quantities with a quantity_spec being the instantiation derived from
|
||||
* 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>;
|
||||
|
||||
/**
|
||||
@@ -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
|
||||
* all quantity-specific information.
|
||||
*/
|
||||
template<typename T>
|
||||
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) {
|
||||
{ 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 template<typename T>
|
||||
concept QuantityLike = !Quantity<T> && detail::QuantityLikeImpl<T, quantity_like_traits> && requires {
|
||||
typename quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>;
|
||||
};
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
} // namespace mp_units
|
||||
|
||||
@@ -248,13 +248,12 @@ public:
|
||||
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>,
|
||||
quantity_type>
|
||||
constexpr explicit(
|
||||
is_specialization_of<decltype(quantity_point_like_traits<QP>::to_numerical_value(std::declval<QP>())),
|
||||
convert_explicitly> ||
|
||||
quantity_point_like_traits<QP>::explicit_import ||
|
||||
!std::convertible_to<
|
||||
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>, quantity_type>)
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
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))
|
||||
{
|
||||
}
|
||||
@@ -371,10 +370,7 @@ public:
|
||||
std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>
|
||||
[[nodiscard]] explicit(
|
||||
is_specialization_of<
|
||||
decltype(quantity_point_like_traits<QP>::from_numerical_value(
|
||||
quantity_from_origin_is_an_implementation_detail_.numerical_value_is_an_implementation_detail_)),
|
||||
convert_explicitly> ||
|
||||
quantity_point_like_traits<QP>::explicit_export ||
|
||||
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
@@ -384,8 +380,7 @@ public:
|
||||
std::is_nothrow_copy_constructible_v<rep>)
|
||||
{
|
||||
return quantity_point_like_traits<QP>::from_numerical_value(
|
||||
quantity_from_origin_is_an_implementation_detail_.numerical_value_is_an_implementation_detail_)
|
||||
.value;
|
||||
quantity_from_origin_is_an_implementation_detail_.numerical_value_is_an_implementation_detail_);
|
||||
}
|
||||
|
||||
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,
|
||||
typename quantity_point_like_traits<QP>::rep>>
|
||||
[[nodiscard]] explicit(
|
||||
is_specialization_of<
|
||||
decltype(quantity_point_like_traits<QP>::from_numerical_value(
|
||||
quantity_from_origin_is_an_implementation_detail_.numerical_value_is_an_implementation_detail_)),
|
||||
convert_explicitly> ||
|
||||
quantity_point_like_traits<QP>::explicit_export ||
|
||||
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
@@ -406,8 +398,7 @@ public:
|
||||
std::is_nothrow_move_constructible_v<rep>)
|
||||
{
|
||||
return quantity_point_like_traits<QP>::from_numerical_value(
|
||||
std::move(quantity_from_origin_is_an_implementation_detail_).numerical_value_is_an_implementation_detail_)
|
||||
.value;
|
||||
std::move(quantity_from_origin_is_an_implementation_detail_).numerical_value_is_an_implementation_detail_);
|
||||
}
|
||||
|
||||
// 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>;
|
||||
|
||||
template<QuantityPointLike QP>
|
||||
explicit(is_specialization_of<decltype(quantity_point_like_traits<QP>::to_numerical_value(std::declval<QP>())),
|
||||
convert_explicitly>) quantity_point(QP)
|
||||
explicit(quantity_point_like_traits<QP>::explicit_import) 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>;
|
||||
|
||||
|
||||
@@ -135,19 +135,9 @@ concept QuantityPointOf =
|
||||
* all quantity_point-specific information.
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename T>
|
||||
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;
|
||||
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>;
|
||||
concept QuantityPointLike = !QuantityPoint<T> && detail::QuantityLikeImpl<T, quantity_point_like_traits> && requires {
|
||||
typename quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin,
|
||||
typename quantity_point_like_traits<T>::rep>;
|
||||
};
|
||||
|
||||
} // namespace mp_units
|
||||
|
||||
Reference in New Issue
Block a user