feat: is_kind support added to quantity_spec definition

This commit is contained in:
Mateusz Pusz
2023-05-02 21:39:25 +02:00
parent bc63ab23e1
commit 82b18fc44c

View File

@@ -155,6 +155,9 @@ template<typename, auto...>
#endif #endif
struct quantity_spec; struct quantity_spec;
inline constexpr struct is_kind {
} is_kind;
/** /**
* @brief Specialization defining a base quantity * @brief Specialization defining a base quantity
* *
@@ -236,7 +239,7 @@ template<detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_charac
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>) requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<Eq, Args...> : detail::quantity_spec_interface { struct quantity_spec<Eq, Args...> : detail::quantity_spec_interface {
#else #else
template<typename Self, detail::IntermediateDerivedQuantitySpec auto Eq, auto... Args> template<typename Self, detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>) requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self> { struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self> {
#endif #endif
@@ -270,13 +273,14 @@ struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self>
* *
* @tparam Q quantity specification of a parent quantity * @tparam Q quantity specification of a parent quantity
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar * @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
* or `is_kind` in case the quantity starts a new hierarchy tree of a kind
*/ */
#ifdef __cpp_explicit_this_parameter #ifdef __cpp_explicit_this_parameter
template<detail::NamedQuantitySpec auto Q, one_of<quantity_character> auto... Args> template<detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>) requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<Q, Args...> : std::remove_const_t<decltype(Q)> { struct quantity_spec<QS, Args...> : std::remove_const_t<decltype(QS)> {
#else #else
template<typename Self, detail::NamedQuantitySpec auto QS, auto... Args> template<typename Self, detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>) requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> { struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
#endif #endif
@@ -325,17 +329,18 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
* *
* @tparam Q quantity specification of a parent quantity * @tparam Q quantity specification of a parent quantity
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar * @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
* or `is_kind` in case the quantity starts a new hierarchy tree of a kind
*/ */
#ifdef __cpp_explicit_this_parameter #ifdef __cpp_explicit_this_parameter
template<detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq, template<detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
one_of<quantity_character> auto... Args> one_of<quantity_character, struct is_kind> auto... Args>
requires(!requires { QS._equation_; } || requires(!requires { QS._equation_; } ||
(requires { QS._equation_; } && (explicitly_convertible(Eq, QS._equation_)))) && (requires { QS._equation_; } && (explicitly_convertible(Eq, QS._equation_)))) &&
(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>) (... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<QS, Eq, Args...> : quantity_spec<QS, Args...> { struct quantity_spec<QS, Eq, Args...> : quantity_spec<QS, Args...> {
#else #else
template<typename Self, detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq, template<typename Self, detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
auto... Args> one_of<quantity_character, struct is_kind> auto... Args>
requires(!requires { QS._equation_; } || requires(!requires { QS._equation_; } ||
(requires { QS._equation_; } && (explicitly_convertible(Eq, QS._equation_)))) && (requires { QS._equation_; } && (explicitly_convertible(Eq, QS._equation_)))) &&
(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>) (... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
@@ -443,7 +448,6 @@ template<detail::QuantitySpecWithNoSpecifiers auto Q>
requires(get_kind(Q) == Q) requires(get_kind(Q) == Q)
inline constexpr kind_of_<Q> kind_of; inline constexpr kind_of_<Q> kind_of;
namespace detail { namespace detail {
template<> template<>
@@ -589,7 +593,7 @@ template<QuantitySpec Q>
requires requires { Q::_equation_; } requires requires { Q::_equation_; }
[[nodiscard]] consteval bool defines_equation(Q) [[nodiscard]] consteval bool defines_equation(Q)
{ {
if constexpr (requires { Q::_parent_; }) if constexpr (requires { Q::_parent_._equation_; })
return Q::_parent_._equation_ != Q::_equation_; return Q::_parent_._equation_ != Q::_equation_;
else else
return true; return true;
@@ -1263,14 +1267,14 @@ template<QuantitySpec From, QuantitySpec To>
else else
return convertible_impl(from_kind, get_kind(explode<get_complexity(from_kind)>(to_kind).quantity)); return convertible_impl(from_kind, get_kind(explode<get_complexity(from_kind)>(to_kind).quantity));
} else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) { } else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) {
if constexpr (get_kind(from) != get_kind(to)) if constexpr (have_common_base(from, to)) {
return no;
else if constexpr (have_common_base(from, to)) {
if (std::derived_from<From, To>) if (std::derived_from<From, To>)
return yes; return yes;
else else
return std::derived_from<To, From> ? explicit_conversion : cast; return std::derived_from<To, From> ? explicit_conversion : cast;
} else if constexpr (get_complexity(from) != get_complexity(to)) { } else if constexpr (get_kind(from) != get_kind(to))
return no;
else if constexpr (get_complexity(from) != get_complexity(to)) {
if constexpr (get_complexity(from) > get_complexity(to)) if constexpr (get_complexity(from) > get_complexity(to))
return convertible_impl(explode<get_complexity(to)>(from).quantity, to); return convertible_impl(explode<get_complexity(to)>(from).quantity, to);
else { else {
@@ -1327,8 +1331,19 @@ template<QuantitySpec Q>
requires requires(Q q) { get_kind(q); } requires requires(Q q) { get_kind(q); }
using to_kind = std::remove_const_t<decltype(get_kind(Q{}))>; using to_kind = std::remove_const_t<decltype(get_kind(Q{}))>;
#ifdef __cpp_explicit_this_parameter
template<NamedQuantitySpec auto QS, auto... Args>
[[nodiscard]] consteval bool defined_as_kind(quantity_spec<QS, Args...>)
#else
template<typename Self, NamedQuantitySpec auto QS, auto... Args>
[[nodiscard]] consteval bool defined_as_kind(quantity_spec<Self, QS, Args...>)
#endif
{
return contains<struct is_kind, Args...>();
} }
} // namespace detail
template<QuantitySpec Q> template<QuantitySpec Q>
[[nodiscard]] consteval auto remove_kind(Q q) [[nodiscard]] consteval auto remove_kind(Q q)
{ {
@@ -1344,8 +1359,17 @@ template<QuantitySpec Q>
template<QuantitySpec Q> template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q) [[nodiscard]] consteval QuantitySpec auto get_kind(Q q)
{ {
auto defined_as_kind = [](auto qq) {
if constexpr (requires { detail::defined_as_kind(qq); })
return detail::defined_as_kind(qq);
else
return false;
};
if constexpr (QuantityKindSpec<Q>) { if constexpr (QuantityKindSpec<Q>) {
return remove_kind(q); return remove_kind(q);
} else if constexpr (defined_as_kind(q)) {
return q;
} else if constexpr (requires { Q::_parent_; }) { } else if constexpr (requires { Q::_parent_; }) {
return get_kind(Q::_parent_); return get_kind(Q::_parent_);
} else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) { } else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) {