refactor: 💥 convertibility traits and concepts refactored to use bool flags instead of wrappers

This commit is contained in:
Mateusz Pusz
2024-10-29 13:15:10 +01:00
parent 18525beb31
commit 975025f88a
8 changed files with 110 additions and 138 deletions
@@ -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
+5 -11
View File
@@ -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