From f49b4c6f5f210f9c364eac5eafd6ccd3356458e7 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 14 Jun 2024 13:30:57 +0200 Subject: [PATCH] refactor: compile-time optimizations reverted --- .../mp-units/bits/get_associated_quantity.h | 24 +- .../mp-units/bits/quantity_spec_hierarchy.h | 52 +- src/core/include/mp-units/bits/sudo_cast.h | 9 +- src/core/include/mp-units/ext/prime.h | 30 +- .../include/mp-units/framework/dimension.h | 18 +- .../mp-units/framework/expression_template.h | 54 +- .../include/mp-units/framework/magnitude.h | 74 +- .../include/mp-units/framework/quantity.h | 3 +- .../mp-units/framework/quantity_spec.h | 852 +++++++++--------- .../framework/quantity_spec_concepts.h | 7 +- .../include/mp-units/framework/reference.h | 2 +- src/core/include/mp-units/framework/unit.h | 138 ++- .../mp-units/framework/unit_concepts.h | 4 +- .../include/mp-units/systems/si/chrono.h | 12 +- test/static/prime_test.cpp | 22 +- 15 files changed, 621 insertions(+), 680 deletions(-) diff --git a/src/core/include/mp-units/bits/get_associated_quantity.h b/src/core/include/mp-units/bits/get_associated_quantity.h index 10640ea9..881c61e8 100644 --- a/src/core/include/mp-units/bits/get_associated_quantity.h +++ b/src/core/include/mp-units/bits/get_associated_quantity.h @@ -34,25 +34,24 @@ template template [[nodiscard]] consteval auto all_are_kinds(power) { - return decltype(all_are_kinds(U{})){}; + return all_are_kinds(U{}); } template -[[nodiscard]] consteval auto all_are_kinds(type_list, type_list) +[[nodiscard]] consteval bool all_are_kinds(type_list, type_list) { - return std::bool_constant<((... && decltype(all_are_kinds(Nums{}))::value) && - (... && decltype(all_are_kinds(Dens{}))::value))>{}; + return (... && all_are_kinds(Nums{})) && (... && all_are_kinds(Dens{})); } template [[nodiscard]] consteval auto all_are_kinds(U) { if constexpr (requires { U::quantity_spec; }) - return std::bool_constant>>{}; + return QuantityKindSpec>; else if constexpr (requires { U::reference_unit; }) - return decltype(all_are_kinds(U::reference_unit)){}; + return all_are_kinds(U::reference_unit); else if constexpr (requires { typename U::_num_; }) { - return decltype(all_are_kinds(typename U::_num_{}, typename U::_den_{})){}; + return all_are_kinds(typename U::_num_{}, typename U::_den_{}); } } @@ -68,21 +67,20 @@ template if constexpr (requires { U::quantity_spec; }) return remove_kind(U::quantity_spec); else if constexpr (requires { U::reference_unit; }) - return decltype(get_associated_quantity_impl(U::reference_unit)){}; + return get_associated_quantity_impl(U::reference_unit); else if constexpr (requires { typename U::_num_; }) { - return decltype(expr_map(u)){}; + return expr_map(u); } } template [[nodiscard]] consteval auto get_associated_quantity(U u) { - constexpr bool all_kinds = decltype(all_are_kinds(u)){}; + constexpr bool all_kinds = all_are_kinds(u); if constexpr (all_kinds) - return kind_of; + return kind_of; else - return decltype(get_associated_quantity_impl(u)){}; + return get_associated_quantity_impl(u); } } // namespace mp_units::detail diff --git a/src/core/include/mp-units/bits/quantity_spec_hierarchy.h b/src/core/include/mp-units/bits/quantity_spec_hierarchy.h index 5a3c0b70..46c2006a 100644 --- a/src/core/include/mp-units/bits/quantity_spec_hierarchy.h +++ b/src/core/include/mp-units/bits/quantity_spec_hierarchy.h @@ -26,12 +26,12 @@ namespace mp_units::detail { -[[nodiscard]] consteval auto hierarchy_path_length(QuantitySpec auto q) +[[nodiscard]] consteval std::size_t hierarchy_path_length(QuantitySpec auto q) { if constexpr (requires { q._parent_; }) - return std::integral_constant{}; + return hierarchy_path_length(q._parent_) + 1; else - return std::integral_constant{}; + return 1; } template @@ -41,67 +41,65 @@ template if constexpr (Offset == 0) return q; else if constexpr (requires { q._parent_; }) - return decltype(hierarchy_path_advance(q._parent_)){}; + return hierarchy_path_advance(q._parent_); } template -[[nodiscard]] consteval auto have_common_base_in_hierarchy_of_equal_length(A a, B b) +[[nodiscard]] consteval bool have_common_base_in_hierarchy_of_equal_length(A a, B b) { if constexpr (is_same_v) - return std::true_type{}; + return true; else if constexpr (requires { a._parent_; }) - return decltype(have_common_base_in_hierarchy_of_equal_length(a._parent_, b._parent_)){}; + return have_common_base_in_hierarchy_of_equal_length(a._parent_, b._parent_); else - return std::false_type{}; + return false; } template -[[nodiscard]] consteval auto have_common_base(A a, B b) +[[nodiscard]] consteval bool have_common_base(A a, B b) { - constexpr std::size_t a_length = decltype(hierarchy_path_length(A{}))::value; - constexpr std::size_t b_length = decltype(hierarchy_path_length(B{}))::value; + constexpr std::size_t a_length = hierarchy_path_length(A{}); + constexpr std::size_t b_length = hierarchy_path_length(B{}); if constexpr (a_length > b_length) - return decltype(have_common_base_in_hierarchy_of_equal_length( - decltype(hierarchy_path_advance(a)){}, b)){}; + return have_common_base_in_hierarchy_of_equal_length(hierarchy_path_advance(a), b); else - return decltype(have_common_base_in_hierarchy_of_equal_length( - a, decltype(hierarchy_path_advance(b)){})){}; + return have_common_base_in_hierarchy_of_equal_length(a, hierarchy_path_advance(b)); } template - requires(decltype(have_common_base_in_hierarchy_of_equal_length(A{}, B{}))::value) + requires(have_common_base_in_hierarchy_of_equal_length(A{}, B{})) [[nodiscard]] consteval QuantitySpec auto get_common_base_for_hierarchy_of_equal_length(A a, B b) { if constexpr (is_same_v) return a; else - return decltype(get_common_base_for_hierarchy_of_equal_length(a._parent_, b._parent_)){}; + return get_common_base_for_hierarchy_of_equal_length(a._parent_, b._parent_); } template - requires(decltype(have_common_base(A{}, B{}))::value) + requires(have_common_base(A{}, B{})) [[nodiscard]] consteval QuantitySpec auto get_common_base(A a, B b) { - constexpr std::size_t a_length = decltype(hierarchy_path_length(A{}))::value; - constexpr std::size_t b_length = decltype(hierarchy_path_length(B{}))::value; + constexpr std::size_t a_length = hierarchy_path_length(A{}); + constexpr std::size_t b_length = hierarchy_path_length(B{}); if constexpr (a_length > b_length) - return decltype(get_common_base_for_hierarchy_of_equal_length(hierarchy_path_advance(a), b)){}; + return get_common_base_for_hierarchy_of_equal_length(hierarchy_path_advance(a), b); else - return decltype(get_common_base_for_hierarchy_of_equal_length(a, hierarchy_path_advance(b))){}; + return get_common_base_for_hierarchy_of_equal_length(a, hierarchy_path_advance(b)); } template -[[nodiscard]] consteval auto is_child_of(Child ch, Parent) +[[nodiscard]] consteval bool is_child_of(Child ch, Parent p) { if constexpr (Child{} == Parent{}) return std::true_type{}; else { - constexpr std::size_t child_length = decltype(hierarchy_path_length(Child{}))::value; - constexpr std::size_t parent_length = decltype(hierarchy_path_length(Parent{}))::value; + constexpr std::size_t child_length = hierarchy_path_length(Child{}); + constexpr std::size_t parent_length = hierarchy_path_length(Parent{}); if constexpr (parent_length > child_length) - return std::false_type{}; + return false; else - return std::bool_constant(ch) == Parent{}>{}; + return hierarchy_path_advance(ch) == p; } } diff --git a/src/core/include/mp-units/bits/sudo_cast.h b/src/core/include/mp-units/bits/sudo_cast.h index ae3aa781..322423b4 100644 --- a/src/core/include/mp-units/bits/sudo_cast.h +++ b/src/core/include/mp-units/bits/sudo_cast.h @@ -64,11 +64,10 @@ template // warnings on conversions } else { // scale the number - constexpr Magnitude auto c_mag = - decltype(decltype(get_canonical_unit(q_unit))::mag / decltype(get_canonical_unit(To::unit))::mag){}; - constexpr Magnitude auto num = decltype(numerator(c_mag)){}; - constexpr Magnitude auto den = decltype(denominator(c_mag)){}; - constexpr Magnitude auto irr = decltype(c_mag * decltype(den / num){}){}; + constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / get_canonical_unit(To::unit).mag; + constexpr Magnitude auto num = numerator(c_mag); + constexpr Magnitude auto den = denominator(c_mag); + constexpr Magnitude auto irr = c_mag * (den / num); using c_rep_type = maybe_common_type::rep, typename To::rep>; using c_mag_type = common_magnitude_type; using multiplier_type = conditional< diff --git a/src/core/include/mp-units/ext/prime.h b/src/core/include/mp-units/ext/prime.h index 4d253cf2..31d4f2cc 100644 --- a/src/core/include/mp-units/ext/prime.h +++ b/src/core/include/mp-units/ext/prime.h @@ -157,30 +157,22 @@ struct wheel_factorizer { static constexpr auto coprimes_in_first_wheel = coprimes_up_to(wheel_size, basis); - template - [[nodiscard]] static consteval auto find_first_factor() + [[nodiscard]] static consteval std::uintmax_t find_first_factor(std::uintmax_t n) { - constexpr std::uintmax_t res = [] { - if (const auto k = detail::get_first_of(basis, [&](auto p) { return first_factor_maybe(N, p); })) return *k; + if (const auto k = detail::get_first_of(basis, [&](auto p) { return first_factor_maybe(n, p); })) return *k; - if (const auto k = detail::get_first_of(std::next(begin(coprimes_in_first_wheel)), end(coprimes_in_first_wheel), - [&](auto p) { return first_factor_maybe(N, p); })) + if (const auto k = detail::get_first_of(std::next(begin(coprimes_in_first_wheel)), end(coprimes_in_first_wheel), + [&](auto p) { return first_factor_maybe(n, p); })) + return *k; + + for (std::size_t wheel = wheel_size; wheel < n; wheel += wheel_size) + if (const auto k = + detail::get_first_of(coprimes_in_first_wheel, [&](auto p) { return first_factor_maybe(n, wheel + p); })) return *k; - - for (std::size_t wheel = wheel_size; wheel < N; wheel += wheel_size) - if (const auto k = - detail::get_first_of(coprimes_in_first_wheel, [&](auto p) { return first_factor_maybe(N, wheel + p); })) - return *k; - return N; - }(); - return std::integral_constant{}; + return n; } - template - [[nodiscard]] static consteval auto is_prime() - { - return std::bool_constant<(N > 1 && decltype(find_first_factor())::value == N)>{}; - } + [[nodiscard]] static consteval bool is_prime(std::size_t n) { return (n > 1) && find_first_factor(n) == n; } }; } // namespace mp_units::detail diff --git a/src/core/include/mp-units/framework/dimension.h b/src/core/include/mp-units/framework/dimension.h index 74554a9f..71d24719 100644 --- a/src/core/include/mp-units/framework/dimension.h +++ b/src/core/include/mp-units/framework/dimension.h @@ -159,15 +159,15 @@ struct is_dimension_one : std::true_type {}; MP_UNITS_EXPORT template [[nodiscard]] consteval Dimension auto operator*(Lhs, Rhs) { - return decltype(detail::expr_multiply(Lhs{}, Rhs{})){}; + return detail::expr_multiply( + Lhs{}, Rhs{}); } MP_UNITS_EXPORT template [[nodiscard]] consteval Dimension auto operator/(Lhs, Rhs) { - return decltype(detail::expr_divide(Lhs{}, Rhs{})){}; + return detail::expr_divide(Lhs{}, + Rhs{}); } namespace detail { @@ -191,7 +191,7 @@ template return is_same_v || detail::derived_from_the_same_base_dimension(lhs, rhs); } -[[nodiscard]] consteval Dimension auto inverse(Dimension auto d) { return decltype(dimension_one / d){}; } +[[nodiscard]] consteval Dimension auto inverse(Dimension auto d) { return dimension_one / d; } /** * @brief Computes the value of a dimension raised to the `Num/Den` power @@ -212,8 +212,8 @@ template else return derived_dimension>{}; } else - return decltype(detail::expr_pow(d)){}; + return detail::expr_pow(d); } /** @@ -223,7 +223,7 @@ template * * @return Dimension The result of computation */ -[[nodiscard]] consteval Dimension auto sqrt(Dimension auto d) { return decltype(pow<1, 2>(d)){}; } +[[nodiscard]] consteval Dimension auto sqrt(Dimension auto d) { return pow<1, 2>(d); } /** * @brief Computes the cubic root of a dimension @@ -232,7 +232,7 @@ template * * @return Dimension The result of computation */ -[[nodiscard]] consteval Dimension auto cbrt(Dimension auto d) { return decltype(pow<1, 3>(d)){}; } +[[nodiscard]] consteval Dimension auto cbrt(Dimension auto d) { return pow<1, 3>(d); } struct dimension_symbol_formatting { diff --git a/src/core/include/mp-units/framework/expression_template.h b/src/core/include/mp-units/framework/expression_template.h index c82e3b16..0e1c0dc2 100644 --- a/src/core/include/mp-units/framework/expression_template.h +++ b/src/core/include/mp-units/framework/expression_template.h @@ -362,7 +362,7 @@ template; // the usage of `std::identity` below helps to resolve an using alias identifier to the actual // type identifier in the clang compile-time errors - return std::identity{}(decltype(expr_make_spec_impl()){}); + return std::identity{}(expr_make_spec_impl()); } /** @@ -384,19 +384,19 @@ template typename To, typename OneType, template && is_specialization_of) { // two derived dimensions - return decltype(get_optimized_expression, - type_list_merge_sorted, - OneType, Pred, To>()){}; + return get_optimized_expression, + type_list_merge_sorted, OneType, + Pred, To>(); } else if constexpr (is_specialization_of) { - return decltype(get_optimized_expression, Pred>, - typename Lhs::_den_, OneType, Pred, To>()){}; + return get_optimized_expression, Pred>, + typename Lhs::_den_, OneType, Pred, To>(); } else if constexpr (is_specialization_of) { - return decltype(get_optimized_expression, Pred>, - typename Rhs::_den_, OneType, Pred, To>()){}; + return get_optimized_expression, Pred>, + typename Rhs::_den_, OneType, Pred, To>(); } else { // two base dimensions - return decltype(get_optimized_expression, type_list, Pred>, type_list<>, - OneType, Pred, To>()){}; + return get_optimized_expression, type_list, Pred>, type_list<>, OneType, + Pred, To>(); } } @@ -418,19 +418,18 @@ template typename To, typename OneType, template) { return lhs; } else if constexpr (is_same_v) { - return decltype(expr_divide(To<>{}, rhs)){}; + return expr_divide(To<>{}, rhs); } else if constexpr (is_specialization_of && is_specialization_of) { // two derived entities - return decltype(get_optimized_expression, - type_list_merge_sorted, - OneType, Pred, To>()){}; + return get_optimized_expression, + type_list_merge_sorted, OneType, + Pred, To>(); } else if constexpr (is_specialization_of) { - return decltype(get_optimized_expression, Pred>, OneType, - Pred, To>()){}; + return get_optimized_expression< + typename Lhs::_num_, type_list_merge_sorted, Pred>, OneType, Pred, To>(); } else if constexpr (is_specialization_of) { - return decltype(get_optimized_expression, Pred>, - typename Rhs::_num_, OneType, Pred, To>()){}; + return get_optimized_expression, Pred>, + typename Rhs::_num_, OneType, Pred, To>(); } else { // two named entities return To>{}; @@ -450,7 +449,7 @@ template typename To, typename OneType, typename T> if constexpr (is_specialization_of) // the usage of `std::identity` below helps to resolve an using alias identifier to the actual // type identifier in the clang compile-time errors - return std::identity{}(decltype(expr_make_spec_impl()){}); + return std::identity{}(expr_make_spec_impl()); else return To>{}; } @@ -461,9 +460,8 @@ template typename To requires detail::non_zero [[nodiscard]] consteval auto expr_pow_impl(type_list, type_list) { - return decltype(detail::get_optimized_expression...>, - type_list...>, OneType, Pred, - To>()){}; + return detail::get_optimized_expression...>, + type_list...>, OneType, Pred, To>(); } @@ -482,7 +480,7 @@ template typename To requires detail::non_zero [[nodiscard]] consteval auto expr_pow(T) { - return decltype(expr_pow_impl(typename T::_num_{}, typename T::_den_{})){}; + return expr_pow_impl(typename T::_num_{}, typename T::_den_{}); } @@ -529,7 +527,7 @@ template template [[nodiscard]] consteval auto map_power(power) { - return decltype(pow(T{})){}; + return pow(T{}); } template typename Proj, template typename To, typename OneType, @@ -537,8 +535,8 @@ template typename Proj, template typename To, ty expr_type_projectable... Dens> [[nodiscard]] consteval auto expr_map_impl(type_list, type_list) { - return decltype(decltype((OneType{} * ... * map_power(typename expr_type_map::type{}))){} / - decltype((OneType{} * ... * map_power(typename expr_type_map::type{}))){}){}; + return (OneType{} * ... * map_power(typename expr_type_map::type{})) / + (OneType{} * ... * map_power(typename expr_type_map::type{})); } /** @@ -557,7 +555,7 @@ template typename Proj, template typename To, ty if constexpr (type_list_size + type_list_size == 0) return OneType{}; else - return decltype(expr_map_impl(typename T::_num_{}, typename T::_den_{})){}; + return expr_map_impl(typename T::_num_{}, typename T::_den_{}); } } // namespace detail diff --git a/src/core/include/mp-units/framework/magnitude.h b/src/core/include/mp-units/framework/magnitude.h index 66cec209..fb547c62 100644 --- a/src/core/include/mp-units/framework/magnitude.h +++ b/src/core/include/mp-units/framework/magnitude.h @@ -476,16 +476,16 @@ namespace detail { template // requires detail::is_element_pack_valid struct magnitude { - [[nodiscard]] friend consteval auto is_integral(const magnitude&) + [[nodiscard]] friend consteval bool is_integral(const magnitude&) { using namespace detail; // needed for recursive case when magnitudes are in the MagnitudeSpec - return std::bool_constant<(is_integral(Ms) && ...)>{}; + return (is_integral(Ms) && ...); } - [[nodiscard]] friend consteval auto is_rational(const magnitude&) + [[nodiscard]] friend consteval bool is_rational(const magnitude&) { using namespace detail; // needed for recursive case when magnitudes are in the MagnitudeSpec - return std::bool_constant<(is_rational(Ms) && ...)>{}; + return (is_rational(Ms) && ...); } }; @@ -508,13 +508,12 @@ inline constexpr bool is_specialization_of_magnitude> = true; } // namespace detail -MP_UNITS_EXPORT_BEGIN /** * @brief The value of a Magnitude in a desired type T. */ template - requires(decltype(is_integral(magnitude{}))::value) || treat_as_floating_point + requires(is_integral(magnitude{})) || treat_as_floating_point constexpr T get_value(const magnitude&) { // Force the expression to be evaluated in a constexpr context, to catch, e.g., overflow. @@ -522,6 +521,8 @@ constexpr T get_value(const magnitude&) return result; } +MP_UNITS_EXPORT_BEGIN + /** * @brief A convenient Magnitude constant for pi, which we can manipulate like a regular number. */ @@ -556,21 +557,21 @@ template if constexpr (Num == 0) { return magnitude<>{}; } else { - return decltype(magnitude()...>{}){}; + return magnitude< + detail::power_v_or_T()...>{}; } } template [[nodiscard]] consteval auto sqrt(magnitude m) { - return decltype(pow<1, 2>(m)){}; + return pow<1, 2>(m); } template [[nodiscard]] consteval auto cbrt(magnitude m) { - return decltype(pow<1, 3>(m)){}; + return pow<1, 3>(m); } MP_UNITS_EXPORT_END @@ -613,13 +614,13 @@ template // Shortcut for the "pure prepend" case, which makes it easier to implement some of the other cases. return magnitude{}; } else { - return decltype(magnitude

{} * (decltype(magnitude{} * magnitude{}){})){}; + return magnitude

{} * (magnitude{} * magnitude{}); } } else if constexpr (less(H2, H1)) { - return decltype(magnitude

{} * (decltype(magnitude{} * magnitude{}){})){}; + return magnitude

{} * (magnitude{} * magnitude{}); } else { if constexpr (is_same_v) { - constexpr auto partial_product = decltype(magnitude{} * magnitude{}){}; + constexpr auto partial_product = magnitude{} * magnitude{}; if constexpr (get_exponent(H1) + get_exponent(H2) == 0) { return partial_product; } else { @@ -629,13 +630,13 @@ template if constexpr (get_exponent(new_head) == 0) { return partial_product; } else { - return decltype(magnitude{} * partial_product){}; + return magnitude{} * partial_product; } } } else if constexpr (is_named_magnitude) { - return decltype(magnitude

{} * decltype((magnitude{} * magnitude{})){}){}; + return magnitude

{} * (magnitude{} * magnitude{}); } else { - return decltype(magnitude

{} * decltype((magnitude{} * magnitude{})){}){}; + return magnitude

{} * (magnitude{} * magnitude{}); } } } @@ -643,7 +644,7 @@ template //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Magnitude quotient implementation. -[[nodiscard]] consteval auto operator/(Magnitude auto l, Magnitude auto r) { return decltype(l * pow<-1>(r)){}; } +[[nodiscard]] consteval auto operator/(Magnitude auto l, Magnitude auto r) { return l * pow<-1>(r); } MP_UNITS_EXPORT_END @@ -670,10 +671,10 @@ template template [[nodiscard]] consteval auto numerator(magnitude) { - return decltype((decltype(detail::integer_part(magnitude{})){} * ... * magnitude<>{})){}; + return (detail::integer_part(magnitude{}) * ... * magnitude<>{}); } -[[nodiscard]] consteval auto denominator(Magnitude auto m) { return decltype(numerator(pow<-1>(m))){}; } +[[nodiscard]] consteval auto denominator(Magnitude auto m) { return numerator(pow<-1>(m)); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Common Magnitude. @@ -713,11 +714,11 @@ template [[nodiscard]] consteval auto common_magnitude(magnitude<>, magnitude<>) { return magnitude<>{}; } [[nodiscard]] consteval auto common_magnitude(magnitude<>, Magnitude auto m) { - return decltype(detail::remove_positive_powers(m)){}; + return detail::remove_positive_powers(m); } [[nodiscard]] consteval auto common_magnitude(Magnitude auto m, magnitude<>) { - return decltype(detail::remove_positive_powers(m)){}; + return detail::remove_positive_powers(m); } // Recursive case for the common Magnitude of any two non-identity Magnitudes. @@ -728,19 +729,17 @@ template if constexpr (detail::get_base_value(H1) < detail::get_base_value(H2)) { // When H1 has the smaller base, prepend to result from recursion. - return decltype(decltype(remove_positive_power(magnitude

{})){} * - decltype(common_magnitude(magnitude{}, magnitude{})){}){}; + return remove_positive_power(magnitude

{}) * common_magnitude(magnitude{}, magnitude{}); } else if constexpr (detail::get_base_value(H2) < detail::get_base_value(H1)) { // When H2 has the smaller base, prepend to result from recursion. - return decltype(decltype(remove_positive_power(magnitude

{})){} * - decltype(common_magnitude(magnitude{}, magnitude{})){}){}; + return remove_positive_power(magnitude

{}) * common_magnitude(magnitude{}, magnitude{}); } else { // When the bases are equal, pick whichever has the lower power. - constexpr auto common_tail = decltype(common_magnitude(magnitude{}, magnitude{})){}; + constexpr auto common_tail = common_magnitude(magnitude{}, magnitude{}); if constexpr (detail::get_exponent(H1) < detail::get_exponent(H2)) { - return decltype(magnitude

{} * common_tail){}; + return magnitude

{} * common_tail; } else { - return decltype(magnitude

{} * common_tail){}; + return magnitude

{} * common_tail; } } } @@ -781,7 +780,7 @@ struct prime_factorization { if constexpr (opt.has_value()) { return opt.value(); // NOLINT(bugprone-unchecked-optional-access) } else { - return static_cast(decltype(factorizer::find_first_factor())::value); + return static_cast(factorizer::find_first_factor(N)); } } @@ -816,15 +815,14 @@ inline constexpr Magnitude auto mag = detail::prime_factorization_v; MP_UNITS_EXPORT template requires detail::gt_zero -inline constexpr Magnitude auto mag_ratio = - decltype(detail::prime_factorization_v / detail::prime_factorization_v){}; +inline constexpr Magnitude auto mag_ratio = detail::prime_factorization_v / detail::prime_factorization_v; /** * @brief Create a Magnitude which is some rational number raised to a rational power. */ MP_UNITS_EXPORT template requires detail::gt_zero -inline constexpr Magnitude auto mag_power = decltype(pow(mag)){}; +inline constexpr Magnitude auto mag_power = pow(mag); namespace detail { @@ -853,14 +851,14 @@ template { constexpr auto exp10 = extract_power_of_10(M); - using base = decltype(M / mag_power<10, exp10>); - using num = decltype(numerator(base{})); - using den = decltype(denominator(base{})); + constexpr Magnitude auto base = M / mag_power<10, exp10>; + constexpr Magnitude auto num = numerator(base); + constexpr Magnitude auto den = denominator(base); // TODO address the below - static_assert(base{} == num{} / den{}, "Printing rational powers, or irrational bases, not yet supported"); + static_assert(base == num / den, "Printing rational powers, or irrational bases, not yet supported"); - constexpr auto num_value = get_value(num{}); - constexpr auto den_value = get_value(den{}); + constexpr auto num_value = get_value(num); + constexpr auto den_value = get_value(den); if constexpr (num_value == 1 && den_value == 1 && exp10 != 0) { return base_multiplier + superscript(); diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index a87fa251..587ab2a2 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -52,8 +52,7 @@ template if constexpr (is_same_v) return true; else - return decltype(is_integral( - decltype(decltype(get_canonical_unit(from))::mag / decltype(get_canonical_unit(to))::mag){}))::value; + return is_integral(get_canonical_unit(from).mag / get_canonical_unit(to).mag); } template diff --git a/src/core/include/mp-units/framework/quantity_spec.h b/src/core/include/mp-units/framework/quantity_spec.h index 04808137..855dd25c 100644 --- a/src/core/include/mp-units/framework/quantity_spec.h +++ b/src/core/include/mp-units/framework/quantity_spec.h @@ -498,7 +498,7 @@ template #ifdef MP_UNITS_API_NO_CRTP template - requires detail::QuantitySpecWithNoSpecifiers && (decltype(detail::get_kind_tree_root(Q{})){} == Q{}) + requires detail::QuantitySpecWithNoSpecifiers && (detail::get_kind_tree_root(Q{}) == Q{}) struct kind_of_ final : Q::_base_type_ { using _base_type_ = kind_of_; static constexpr auto _quantity_spec_ = Q{}; @@ -507,10 +507,10 @@ struct kind_of_ final : Q::_base_type_ { #if MP_UNITS_COMP_CLANG template - requires detail::QuantitySpecWithNoSpecifiers && (decltype(detail::get_kind_tree_root(Q{})){} == Q{}) + requires detail::QuantitySpecWithNoSpecifiers && (detail::get_kind_tree_root(Q{}) == Q{}) #else template - requires(decltype(detail::get_kind_tree_root(Q{})){} == Q{}) + requires(detail::get_kind_tree_root(Q{}) == Q{}) #endif struct kind_of_ final : quantity_spec, Q{}>::_base_type_ { using _base_type_ = kind_of_; @@ -519,7 +519,7 @@ struct kind_of_ final : quantity_spec, Q{}>::_base_type_ { #endif MP_UNITS_EXPORT template - requires(decltype(detail::get_kind_tree_root(Q)){} == Q) + requires(detail::get_kind_tree_root(Q) == Q) inline constexpr kind_of_ kind_of; namespace detail { @@ -551,17 +551,17 @@ MP_UNITS_EXPORT_BEGIN template [[nodiscard]] consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs) { - return detail::clone_kind_of(decltype(detail::expr_multiply( - detail::remove_kind(lhs), detail::remove_kind(rhs))){}); + return detail::clone_kind_of( + detail::expr_multiply( + detail::remove_kind(lhs), detail::remove_kind(rhs))); } template [[nodiscard]] consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs) { return detail::clone_kind_of( - decltype(detail::expr_divide( - detail::remove_kind(lhs), detail::remove_kind(rhs))){}); + detail::expr_divide( + detail::remove_kind(lhs), detail::remove_kind(rhs))); } template @@ -570,7 +570,7 @@ template return is_same_v; } -[[nodiscard]] consteval QuantitySpec auto inverse(QuantitySpec auto q) { return decltype(dimensionless / q){}; } +[[nodiscard]] consteval QuantitySpec auto inverse(QuantitySpec auto q) { return dimensionless / q; } /** @@ -592,8 +592,8 @@ template return q; else if constexpr (detail::DerivedQuantitySpec) return detail::clone_kind_of( - decltype(detail::expr_pow(detail::remove_kind(q))){}); + detail::expr_pow( + detail::remove_kind(q))); else if constexpr (Den == 1) return detail::clone_kind_of(derived_quantity_spec>{}); else @@ -608,7 +608,7 @@ template * * @return QuantitySpec The result of computation */ -[[nodiscard]] consteval QuantitySpec auto sqrt(QuantitySpec auto q) { return decltype(pow<1, 2>(q)){}; } +[[nodiscard]] consteval QuantitySpec auto sqrt(QuantitySpec auto q) { return pow<1, 2>(q); } /** @@ -618,43 +618,42 @@ template * * @return QuantitySpec The result of computation */ -[[nodiscard]] consteval QuantitySpec auto cbrt(QuantitySpec auto q) { return decltype(pow<1, 3>(q)){}; } +[[nodiscard]] consteval QuantitySpec auto cbrt(QuantitySpec auto q) { return pow<1, 3>(q); } MP_UNITS_EXPORT_END namespace detail { template -[[nodiscard]] consteval auto get_complexity(Q); +[[nodiscard]] consteval int get_complexity(Q); template -[[nodiscard]] consteval auto get_complexity(type_list) +[[nodiscard]] consteval int get_complexity(type_list) { - return std::integral_constant{}; + return (0 + ... + get_complexity(Ts{})); } template -[[nodiscard]] consteval auto get_complexity(power) +[[nodiscard]] consteval int get_complexity(power) { - return decltype(get_complexity(Q{})){}; + return get_complexity(Q{}); } template -[[nodiscard]] consteval auto get_complexity(kind_of_) +[[nodiscard]] consteval int get_complexity(kind_of_) { - return decltype(get_complexity(Q{})){}; + return get_complexity(Q{}); } template -[[nodiscard]] consteval auto get_complexity(Q) +[[nodiscard]] consteval int get_complexity(Q) { if constexpr (detail::DerivedQuantitySpec) - return std::integral_constant{}; + return get_complexity(typename Q::_num_{}) + get_complexity(typename Q::_den_{}); else if constexpr (requires { Q::_equation_; }) - return std::integral_constant{}; + return 1 + get_complexity(Q::_equation_); else - return std::integral_constant{}; + return 1; } // dimension_one is always the last one @@ -671,8 +670,8 @@ template } template + bool rhs_eq = requires { Rhs::_equation_; }, ratio lhs_compl = get_complexity(Lhs{}), + ratio rhs_compl = get_complexity(Rhs{})> struct ingredients_less : std::bool_constant<(lhs_compl > rhs_compl) || (lhs_compl == rhs_compl && ingredients_dimension_less(Lhs::dimension, Rhs::dimension)) || @@ -694,19 +693,25 @@ template enum class specs_convertible_result : std::int8_t { no, cast, explicit_conversion, yes }; -template +template struct explode_to_equation_result { - static constexpr QuantitySpec auto equation = Q; - static constexpr specs_convertible_result result = Result; + Q equation; + specs_convertible_result result; }; +#if MP_UNITS_COMP_CLANG + +template +explode_to_equation_result(Q, specs_convertible_result) -> explode_to_equation_result; + +#endif + template requires requires { Q::_equation_; } [[nodiscard]] consteval auto explode_to_equation(Q q) { - return explode_to_equation_result{}; + return explode_to_equation_result{ + Q::_equation_, defines_equation(q) ? specs_convertible_result::yes : specs_convertible_result::explicit_conversion}; } template @@ -714,23 +719,30 @@ template [[nodiscard]] consteval auto explode_to_equation(power) { constexpr ratio exp = power::exponent; - return explode_to_equation_result(Q::_equation_)){}, - (defines_equation(Q{}) ? specs_convertible_result::yes - : specs_convertible_result::explicit_conversion)>{}; + return explode_to_equation_result{ + pow(Q::_equation_), + defines_equation(Q{}) ? specs_convertible_result::yes : specs_convertible_result::explicit_conversion}; } -template +template struct explode_result { - static constexpr QuantitySpec auto quantity = Q; - static constexpr specs_convertible_result result = Result; + Q quantity; + specs_convertible_result result = specs_convertible_result::yes; - template - [[nodiscard]] static consteval auto common_convertibility_with(explode_to_equation_result res) + template + [[nodiscard]] consteval explode_result common_convertibility_with(explode_to_equation_result res) const { - return explode_result{}; + return {quantity, min(result, res.result)}; } }; +#if MP_UNITS_COMP_CLANG + +template +explode_result(Q) -> explode_result; + +#endif + template [[nodiscard]] consteval auto explode(Q q); @@ -740,25 +752,24 @@ template template [[nodiscard]] consteval auto explode(Q, type_list, type_list) { - constexpr auto n = decltype(get_complexity(Num{}))::value; - constexpr auto d = decltype(get_complexity(Den{}))::value; + constexpr auto n = get_complexity(Num{}); + constexpr auto d = get_complexity(Den{}); constexpr auto max_compl = n > d ? n : d; if constexpr (max_compl == Complexity || ((n >= d && !requires { explode_to_equation(Num{}); }) || (n < d && !requires { explode_to_equation(Den{}); }))) - return explode_result{}; + return explode_result{(map_power(Num{}) * ... * map_power(Nums{})) / (map_power(Den{}) * ... * map_power(Dens{}))}; else { if constexpr (n >= d) { - constexpr auto res = decltype(explode_to_equation(Num{})){}; - return decltype(explode( - decltype(decltype((res.equation * ... * map_power(Nums{}))){} / - decltype((map_power(Den{}) * ... * map_power(Dens{}))){}){}))::common_convertibility_with(res); + constexpr auto res = explode_to_equation(Num{}); + return explode((res.equation * ... * map_power(Nums{})) / + (map_power(Den{}) * ... * map_power(Dens{}))) + .common_convertibility_with(res); } else { constexpr auto res = explode_to_equation(Den{}); - return decltype(explode( - decltype(decltype((map_power(Num{}) * ... * map_power(Nums{}))){} / - decltype((res.equation * ... * map_power(Dens{}))){}){}))::common_convertibility_with(res); + return explode((map_power(Num{}) * ... * map_power(Nums{})) / + (res.equation * ... * map_power(Dens{}))) + .common_convertibility_with(res); } } } @@ -766,113 +777,123 @@ template [[nodiscard]] consteval auto explode(Q, type_list, type_list<>) { - constexpr auto n = decltype(get_complexity(Num{}))::value; + constexpr auto n = get_complexity(Num{}); if constexpr (n == Complexity || !requires { explode_to_equation(Num{}); }) - return explode_result{}; + return explode_result{(map_power(Num{}) * ... * map_power(Nums{}))}; else { - constexpr auto res = decltype(explode_to_equation(Num{})){}; - return decltype(explode( - decltype((res.equation * ... * map_power(Nums{}))){}))::common_convertibility_with(res); + constexpr auto res = explode_to_equation(Num{}); + return explode((res.equation * ... * map_power(Nums{}))).common_convertibility_with(res); } } template [[nodiscard]] consteval auto explode(Q, type_list<>, type_list) { - constexpr auto d = decltype(get_complexity(Den{}))::value; + constexpr auto d = get_complexity(Den{}); if constexpr (d == Complexity || !requires { explode_to_equation(Den{}); }) - return explode_result{}; + return explode_result{dimensionless / (map_power(Den{}) * ... * map_power(Dens{}))}; else { - constexpr auto res = decltype(explode_to_equation(Den{})){}; - return decltype(explode( - decltype(dimensionless / - decltype((res.equation * ... * map_power(Dens{}))){}){}))::common_convertibility_with(res); + constexpr auto res = explode_to_equation(Den{}); + return explode(dimensionless / (res.equation * ... * map_power(Dens{}))) + .common_convertibility_with(res); } } template [[nodiscard]] consteval auto explode(Q, type_list<>, type_list<>) { - return explode_result{}; + return explode_result{dimensionless}; } template [[nodiscard]] consteval auto explode(Q q) { - constexpr auto c = decltype(get_complexity(Q{}))::value; + constexpr auto c = get_complexity(Q{}); if constexpr (c > Complexity) - return decltype(explode(q, type_list_sort{}, - type_list_sort{})){}; + return explode(q, type_list_sort{}, + type_list_sort{}); else - return explode_result{}; + return explode_result{q}; } template -[[nodiscard]] consteval auto explode(Q) +[[nodiscard]] consteval auto explode(Q q) { - constexpr auto c = decltype(get_complexity(Q{}))::value; + constexpr auto c = get_complexity(Q{}); if constexpr (c > Complexity && requires { Q::_equation_; }) { - constexpr auto res = decltype(explode_to_equation(Q{})){}; - return decltype(explode(res.equation))::common_convertibility_with(res); + constexpr auto res = explode_to_equation(Q{}); + return explode(res.equation).common_convertibility_with(res); } else - return explode_result{}; + return explode_result{q}; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list num_from, - type_list den_from, - type_list num_to, - type_list den_to); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list num_from, + type_list den_from, + type_list num_to, + type_list den_to); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list, - type_list, type_list); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, + type_list, + type_list, + type_list); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, type_list<>, - type_list, type_list); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, + type_list<>, type_list, + type_list); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, - type_list, type_list<>, - type_list); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, + type_list, + type_list<>, type_list); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, - type_list, type_list, - type_list<>); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, + type_list, + type_list, type_list<>); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, type_list<>, - type_list, type_list<>); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, + type_list<>, type_list, + type_list<>); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list, type_list<>, - type_list); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, + type_list, + type_list<>, type_list); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, type_list, type_list<>, - type_list<>); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, + type_list, type_list<>, + type_list<>); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list, - type_list); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, + type_list, + type_list); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, type_list<>, type_list<>, type_list<>); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, type_list<>, + type_list<>, type_list<>); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list, type_list<>, type_list<>); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list, + type_list<>, type_list<>); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list, type_list<>); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, + type_list, type_list<>); template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list<>, type_list); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, type_list<>, + type_list); -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list<>, type_list<>); +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, type_list<>, + type_list<>); enum class prepend_rest : std::int8_t { no, first, second }; @@ -895,8 +916,8 @@ extract_results(bool, From = {}, To = {}, prepend_rest = {}, Elem = {}) -> extra template [[nodiscard]] consteval auto extract_convertible_quantities(From, To) { - constexpr auto qfrom = decltype(map_power(From{})){}; - constexpr auto qto = decltype(map_power(To{})){}; + constexpr auto qfrom = map_power(From{}); + constexpr auto qto = map_power(To{}); if constexpr (qfrom.dimension == qto.dimension) { if constexpr (is_specialization_of_power && is_specialization_of_power) { constexpr auto cr = common_ratio(From::exponent, To::exponent); @@ -934,63 +955,49 @@ template enum class process_entities : std::int8_t { numerators, denominators, from, to }; template -[[nodiscard]] consteval auto process_num_den(NumFrom num_from, DenFrom den_from, NumTo num_to, DenTo den_to) +[[nodiscard]] consteval specs_convertible_result process_num_den(NumFrom num_from, DenFrom den_from, NumTo num_to, + DenTo den_to) { - constexpr auto res = decltype(convertible_impl(Ext.from, Ext.to))::value; + constexpr auto res = convertible_impl(Ext.from, Ext.to); if constexpr (Ext.prepend == prepend_rest::no) - return std::integral_constant{}; + return min(res, are_ingredients_convertible(num_from, den_from, num_to, den_to)); else { using elem = decltype(Ext.elem); if constexpr (Entities == process_entities::numerators) { if constexpr (Ext.prepend == prepend_rest::first) - return std::integral_constant{}, - den_from, num_to, den_to))::value)>{}; + return min(res, are_ingredients_convertible(type_list_push_front{}, den_from, num_to, den_to)); else - return std::integral_constant{}, - den_to))::value)>{}; + return min(res, are_ingredients_convertible(num_from, den_from, type_list_push_front{}, den_to)); } else { if constexpr (Ext.prepend == prepend_rest::first) - return std::integral_constant{}, num_to, - den_to))::value)>{}; + return min(res, are_ingredients_convertible(num_from, type_list_push_front{}, num_to, den_to)); else - return std::integral_constant{}))::value)>{}; + return min(res, are_ingredients_convertible(num_from, den_from, num_to, type_list_push_front{})); } } } template -[[nodiscard]] consteval auto process_extracted(NumFrom num_from, DenFrom den_from, NumTo num_to, DenTo den_to) +[[nodiscard]] consteval specs_convertible_result process_extracted(NumFrom num_from, DenFrom den_from, NumTo num_to, + DenTo den_to) { if constexpr (Entities == process_entities::numerators || Entities == process_entities::denominators) { - return decltype(process_num_den(num_from, den_from, num_to, den_to)){}; + return process_num_den(num_from, den_from, num_to, den_to); } else { if constexpr (Ext.prepend == prepend_rest::no) - return decltype(are_ingredients_convertible(num_from, den_from, num_to, den_to)){}; + return are_ingredients_convertible(num_from, den_from, num_to, den_to); else { using elem = decltype(Ext.elem); if constexpr (Entities == process_entities::from) { if constexpr (Ext.prepend == prepend_rest::first) - return decltype(are_ingredients_convertible(type_list_push_front{}, den_from, num_to, - den_to)){}; + return are_ingredients_convertible(type_list_push_front{}, den_from, num_to, den_to); else - return decltype(are_ingredients_convertible(num_from, type_list_push_front{}, num_to, - den_to)){}; + return are_ingredients_convertible(num_from, type_list_push_front{}, num_to, den_to); } else { if constexpr (Ext.prepend == prepend_rest::first) - return decltype(are_ingredients_convertible(num_from, den_from, type_list_push_front{}, - den_to)){}; + return are_ingredients_convertible(num_from, den_from, type_list_push_front{}, den_to); else - return decltype(are_ingredients_convertible(num_from, den_from, num_to, - type_list_push_front{})){}; + return are_ingredients_convertible(num_from, den_from, num_to, type_list_push_front{}); } } } @@ -998,485 +1005,442 @@ template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list num_from, - type_list den_from, - type_list num_to, - type_list den_to) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list num_from, + type_list den_from, + type_list num_to, + type_list den_to) { if constexpr (constexpr auto extN = extract_convertible_quantities(NumFrom{}, NumTo{}); extN.same_dimension) - return decltype(process_extracted(type_list{}, den_from, - type_list{}, den_to)){}; + return process_extracted(type_list{}, den_from, + type_list{}, den_to); else if constexpr (constexpr auto extD = extract_convertible_quantities(DenFrom{}, DenTo{}); extD.same_dimension) - return decltype(process_extracted(num_from, type_list{}, num_to, - type_list{})){}; + return process_extracted(num_from, type_list{}, num_to, + type_list{}); else if constexpr (constexpr auto extF = extract_convertible_quantities(NumFrom{}, DenFrom{}); extF.same_dimension) - return decltype(process_extracted(type_list{}, type_list{}, - num_to, den_to)){}; + return process_extracted(type_list{}, type_list{}, num_to, + den_to); else if constexpr (constexpr auto extT = extract_convertible_quantities(NumTo{}, DenTo{}); extT.same_dimension) - return decltype(process_extracted(num_from, den_from, type_list{}, - type_list{})){}; + return process_extracted(num_from, den_from, type_list{}, + type_list{}); else { - constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value; - constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value; - constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value; - constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value; + constexpr auto num_from_compl = get_complexity(NumFrom{}); + constexpr auto den_from_compl = get_complexity(DenFrom{}); + constexpr auto num_to_compl = get_complexity(NumTo{}); + constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto max_compl = max({num_from_compl, num_to_compl, den_from_compl, den_to_compl}); if constexpr (max_compl > 1) { if constexpr (num_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(NumFrom{})){}; - return decltype(convertible_impl(decltype(decltype((res.equation * ... * map_power(NumsFrom{}))){} / - decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype(decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){} / - decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){})){}; + constexpr auto res = explode_to_equation(NumFrom{}); + return convertible_impl( + (res.equation * ... * map_power(NumsFrom{})) / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else if constexpr (den_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(DenFrom{})){}; - return decltype(convertible_impl(decltype(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){} / - decltype((res.equation * ... * map_power(DensFrom{}))){}){}, - decltype(decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){} / - decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){})){}; + constexpr auto res = explode_to_equation(DenFrom{}); + return convertible_impl( + (map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / (res.equation * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else if constexpr (num_to_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(NumTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, decltype(convertible_impl( - decltype(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){} / - decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype(decltype((res.equation * ... * map_power(NumsTo{}))){} / - decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){}))::value)>{}; + constexpr auto res = explode_to_equation(NumTo{}); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / + (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (res.equation * ... * map_power(NumsTo{})) / + (map_power(DenTo{}) * ... * map_power(DensTo{})))); } else { - constexpr auto res = decltype(explode_to_equation(DenTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, - decltype(convertible_impl(decltype(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){} / - decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype(decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){} / - decltype((res.equation * ... * map_power(DensTo{}))){}){}))::value)>{}; + constexpr auto res = explode_to_equation(DenTo{}); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / + (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / + (res.equation * ... * map_power(DensTo{})))); } - } else - return std::integral_constant{}; + } } + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<> num_from, type_list den_from, - type_list num_to, - type_list) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<> num_from, + type_list den_from, + type_list num_to, + type_list) { if constexpr (constexpr auto extD = extract_convertible_quantities(DenFrom{}, DenTo{}); extD.same_dimension) - return decltype(process_extracted(num_from, type_list{}, num_to, - type_list{})){}; + return process_extracted(num_from, type_list{}, num_to, + type_list{}); else if constexpr (constexpr auto extT = extract_convertible_quantities(NumTo{}, DenTo{}); extT.same_dimension) - return decltype(process_extracted(num_from, den_from, type_list{}, - type_list{})){}; + return process_extracted(num_from, den_from, type_list{}, + type_list{}); else { - constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value; - constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value; - constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value; + constexpr auto den_from_compl = get_complexity(DenFrom{}); + constexpr auto num_to_compl = get_complexity(NumTo{}); + constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto max_compl = max({num_to_compl, den_from_compl, den_to_compl}); if constexpr (max_compl > 1) { if constexpr (den_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(DenFrom{})){}; - return decltype(convertible_impl( - decltype(dimensionless / decltype((res.equation * ... * map_power(DensFrom{}))){}){}, - decltype(decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){} / - decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){})){}; + constexpr auto res = explode_to_equation(DenFrom{}); + return convertible_impl( + dimensionless / (res.equation * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else if constexpr (num_to_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(NumTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, - decltype(convertible_impl( - decltype(dimensionless / decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype(decltype((res.equation * ... * map_power(NumsTo{}))){} / - decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){}))::value)>{}; + constexpr auto res = explode_to_equation(NumTo{}); + return min(res.result, convertible_impl(dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (res.equation * ... * map_power(NumsTo{})) / + (map_power(DenTo{}) * ... * map_power(DensTo{})))); } else { - constexpr auto res = decltype(explode_to_equation(DenTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, - decltype(convertible_impl( - decltype(dimensionless / decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype(decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){} / - decltype((res.equation * ... * map_power(DensTo{}))){}){}))::value)>{}; + constexpr auto res = explode_to_equation(DenTo{}); + return min(res.result, convertible_impl(dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / + (res.equation * ... * map_power(DensTo{})))); } - } else - return std::integral_constant{}; + } } + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list num_from, type_list<> den_from, - type_list, - type_list den_to) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list num_from, + type_list<> den_from, + type_list, + type_list den_to) { if constexpr (constexpr auto extN = extract_convertible_quantities(NumFrom{}, NumTo{}); extN.same_dimension) - return decltype(process_extracted(type_list{}, den_from, - type_list{}, den_to)){}; + return process_extracted(type_list{}, den_from, + type_list{}, den_to); else if constexpr (constexpr auto extT = extract_convertible_quantities(NumTo{}, DenTo{}); extT.same_dimension) - return decltype(process_extracted(num_from, den_from, type_list{}, - type_list{})){}; + return process_extracted(num_from, den_from, type_list{}, + type_list{}); else { - constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value; - constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value; - constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value; + constexpr auto num_from_compl = get_complexity(NumFrom{}); + constexpr auto num_to_compl = get_complexity(NumTo{}); + constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto max_compl = max({num_from_compl, num_to_compl, den_to_compl}); if constexpr (max_compl > 1) { if constexpr (num_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(NumFrom{})){}; - return decltype(convertible_impl(decltype((res.equation * ... * map_power(NumsFrom{}))){}, - decltype(decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){} / - decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){})){}; + constexpr auto res = explode_to_equation(NumFrom{}); + return convertible_impl( + (res.equation * ... * map_power(NumsFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else if constexpr (num_to_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(NumTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, decltype(convertible_impl( - decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){}, - decltype(decltype((res.equation * ... * map_power(NumsTo{}))){} / - decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){}))::value)>{}; + constexpr auto res = explode_to_equation(NumTo{}); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), + (res.equation * ... * map_power(NumsTo{})) / + (map_power(DenTo{}) * ... * map_power(DensTo{})))); } else { - constexpr auto res = decltype(explode_to_equation(DenTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, - decltype(convertible_impl(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){}, - decltype(decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){} / - decltype((res.equation * ... * map_power(DensTo{}))){}){}))::value)>{}; + constexpr auto res = explode_to_equation(DenTo{}); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{})) / + (res.equation * ... * map_power(DensTo{})))); } - } else - return std::integral_constant{}; + } } + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list num_from, - type_list, type_list<> num_to, - type_list den_to) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list num_from, + type_list, + type_list<> num_to, + type_list den_to) { if constexpr (constexpr auto extD = extract_convertible_quantities(DenFrom{}, DenTo{}); extD.same_dimension) - return decltype(process_extracted(num_from, type_list{}, num_to, - type_list{})){}; + return process_extracted(num_from, type_list{}, num_to, + type_list{}); else if constexpr (constexpr auto extF = extract_convertible_quantities(NumFrom{}, DenFrom{}); extF.same_dimension) - return decltype(process_extracted(type_list{}, type_list{}, - num_to, den_to)){}; + return process_extracted(type_list{}, type_list{}, num_to, + den_to); else { - constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value; - constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value; - constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value; + constexpr auto num_from_compl = get_complexity(NumFrom{}); + constexpr auto den_from_compl = get_complexity(DenFrom{}); + constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto max_compl = max({num_from_compl, den_from_compl, den_to_compl}); if constexpr (max_compl > 1) { if constexpr (num_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(NumFrom{})){}; - return decltype(convertible_impl( - decltype(decltype((res.equation * ... * map_power(NumsFrom{}))){} / - decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype(dimensionless / decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){})){}; + constexpr auto res = explode_to_equation(NumFrom{}); + return convertible_impl( + (res.equation * ... * map_power(NumsFrom{})) / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + dimensionless / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else if constexpr (den_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(DenFrom{})){}; - return decltype(convertible_impl( - decltype(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){} / - decltype((res.equation * ... * map_power(DensFrom{}))){}){}, - decltype(dimensionless / decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){})){}; + constexpr auto res = explode_to_equation(DenFrom{}); + return convertible_impl( + (map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / (res.equation * ... * map_power(DensFrom{})), + dimensionless / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else { - constexpr auto res = decltype(explode_to_equation(DenTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, - decltype(convertible_impl( - decltype(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){} / - decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype(dimensionless / decltype((res.equation * ... * map_power(DensTo{}))){}){}))::value)>{}; + constexpr auto res = explode_to_equation(DenTo{}); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / + (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + dimensionless / (res.equation * ... * map_power(DensTo{})))); } - } else - return std::integral_constant{}; + } } + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, - type_list den_from, - type_list num_to, type_list<> den_to) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, + type_list den_from, + type_list num_to, + type_list<> den_to) { if constexpr (constexpr auto extN = extract_convertible_quantities(NumFrom{}, NumTo{}); extN.same_dimension) - return decltype(process_extracted(type_list{}, den_from, - type_list{}, den_to)){}; + return process_extracted(type_list{}, den_from, + type_list{}, den_to); else if constexpr (constexpr auto extF = extract_convertible_quantities(NumFrom{}, DenFrom{}); extF.same_dimension) - return decltype(process_extracted(type_list{}, type_list{}, - num_to, den_to)){}; + return process_extracted(type_list{}, type_list{}, num_to, + den_to); else { - constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value; - constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value; - constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value; + constexpr auto num_from_compl = get_complexity(NumFrom{}); + constexpr auto den_from_compl = get_complexity(DenFrom{}); + constexpr auto num_to_compl = get_complexity(NumTo{}); constexpr auto max_compl = max({num_from_compl, num_to_compl, den_from_compl}); if constexpr (max_compl > 1) { if constexpr (num_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(NumFrom{})){}; - return decltype(convertible_impl(decltype(decltype((res.equation * ... * map_power(NumsFrom{}))){} / - decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){})){}; + constexpr auto res = explode_to_equation(NumFrom{}); + return convertible_impl( + (res.equation * ... * map_power(NumsFrom{})) / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{}))); } else if constexpr (den_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(DenFrom{})){}; - return decltype(convertible_impl(decltype(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){} / - decltype((res.equation * ... * map_power(DensFrom{}))){}){}, - decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){})){}; + constexpr auto res = explode_to_equation(DenFrom{}); + return convertible_impl( + (map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / (res.equation * ... * map_power(DensFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{}))); } else { - constexpr auto res = decltype(explode_to_equation(NumTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, - decltype(convertible_impl(decltype(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){} / - decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype((res.equation * ... * map_power(NumsTo{}))){}))::value)>{}; + constexpr auto res = explode_to_equation(NumTo{}); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})) / + (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + (res.equation * ... * map_power(NumsTo{})))); } - } else - return std::integral_constant{}; + } } + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, type_list<> den_from, - type_list, type_list<> den_to) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, + type_list<> den_from, + type_list, + type_list<> den_to) { if constexpr (constexpr auto ext = extract_convertible_quantities(NumFrom{}, NumTo{}); ext.same_dimension) { - return decltype(process_extracted(type_list{}, den_from, - type_list{}, den_to)){}; + return process_extracted(type_list{}, den_from, + type_list{}, den_to); } else { - constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value; - constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value; + constexpr auto num_from_compl = get_complexity(NumFrom{}); + constexpr auto num_to_compl = get_complexity(NumTo{}); constexpr auto max_compl = max(num_from_compl, num_to_compl); if constexpr (max_compl > 1) { if constexpr (num_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(NumFrom{})){}; - return decltype(convertible_impl(decltype((res.equation * ... * map_power(NumsFrom{}))){}, - decltype((map_power(NumTo{}) * ... * map_power(NumsTo{}))){})){}; + constexpr auto res = explode_to_equation(NumFrom{}); + return convertible_impl((res.equation * ... * map_power(NumsFrom{})), + (map_power(NumTo{}) * ... * map_power(NumsTo{}))); } else { - constexpr auto res = decltype(explode_to_equation(NumTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, decltype(convertible_impl(decltype((map_power(NumFrom{}) * ... * map_power(NumsFrom{}))){}, - decltype((res.equation * ... * map_power(NumsTo{}))){}))::value)>{}; + constexpr auto res = explode_to_equation(NumTo{}); + return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), + (res.equation * ... * map_power(NumsTo{})))); } - } else - return std::integral_constant{}; + } } + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<> num_from, type_list, - type_list<> num_to, type_list) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<> num_from, + type_list, + type_list<> num_to, + type_list) { if constexpr (constexpr auto ext = extract_convertible_quantities(DenFrom{}, DenTo{}); ext.same_dimension) - return decltype(process_extracted(num_from, type_list{}, num_to, - type_list{})){}; + return process_extracted(num_from, type_list{}, num_to, + type_list{}); else { - constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value; - constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value; + constexpr auto den_from_compl = get_complexity(DenFrom{}); + constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto max_compl = max(den_from_compl, den_to_compl); if constexpr (max_compl > 1) { if constexpr (den_from_compl == max_compl) { - constexpr auto res = decltype(explode_to_equation(DenFrom{})){}; - return decltype(convertible_impl( - decltype(dimensionless / decltype((res.equation * ... * map_power(DensFrom{}))){}){}, - decltype(dimensionless / decltype((map_power(DenTo{}) * ... * map_power(DensTo{}))){}){})){}; + constexpr auto res = explode_to_equation(DenFrom{}); + return convertible_impl(dimensionless / (res.equation * ... * map_power(DensFrom{})), + dimensionless / (map_power(DenTo{}) * ... * map_power(DensTo{}))); } else { - constexpr auto res = decltype(explode_to_equation(DenTo{})){}; - return std::integral_constant< - specs_convertible_result, - min(res.result, - decltype(convertible_impl( - decltype(dimensionless / decltype((map_power(DenFrom{}) * ... * map_power(DensFrom{}))){}){}, - decltype(dimensionless / decltype((res.equation * ... * map_power(DensTo{}))){}){}))::value)>{}; + constexpr auto res = explode_to_equation(DenTo{}); + return min(res.result, convertible_impl(dimensionless / (map_power(DenFrom{}) * ... * map_power(DensFrom{})), + dimensionless / (res.equation * ... * map_power(DensTo{})))); } - } else - return std::integral_constant{}; + } } + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, type_list, type_list<>, - type_list<>) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, + type_list, type_list<>, + type_list<>) { - if constexpr (decltype(decltype((... * map_power(NumsFrom{}))){} / - decltype((... * map_power(DensFrom{}))){})::dimension == dimension_one) - return std::integral_constant{}; + if constexpr (((... * map_power(NumsFrom{})) / (... * map_power(DensFrom{}))).dimension == dimension_one) + return specs_convertible_result::yes; else - return std::integral_constant{}; + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list, - type_list) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, + type_list, type_list) { - if constexpr (decltype(decltype((... * map_power(NumsTo{}))){} / - decltype((... * map_power(DensTo{}))){})::dimension == dimension_one) - return std::integral_constant{}; + if constexpr (((... * map_power(NumsTo{})) / (... * map_power(DensTo{}))).dimension == dimension_one) + return specs_convertible_result::explicit_conversion; else - return std::integral_constant{}; + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list, type_list<>, type_list<>, type_list<>) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, type_list<>, + type_list<>, type_list<>) { - if constexpr (decltype((... * map_power(NumsFrom{})))::dimension == dimension_one) - return std::integral_constant{}; + if constexpr ((... * map_power(NumsFrom{})).dimension == dimension_one) + return specs_convertible_result::yes; else - return std::integral_constant{}; + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list, type_list<>, type_list<>) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list, + type_list<>, type_list<>) { - if constexpr (decltype((... * map_power(DensFrom{})))::dimension == dimension_one) - return std::integral_constant{}; + if constexpr ((... * map_power(DensFrom{})).dimension == dimension_one) + return specs_convertible_result::yes; else - return std::integral_constant{}; + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list, type_list<>) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, + type_list, type_list<>) { - if constexpr (decltype((... * map_power(NumsTo{})))::dimension == dimension_one) - return std::integral_constant{}; + if constexpr ((... * map_power(NumsTo{})).dimension == dimension_one) + return specs_convertible_result::explicit_conversion; else - return std::integral_constant{}; + return specs_convertible_result::no; } template -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list<>, type_list) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, type_list<>, + type_list) { - if constexpr (decltype((... * map_power(DensTo{})))::dimension == dimension_one) - return std::integral_constant{}; + if constexpr ((... * map_power(DensTo{})).dimension == dimension_one) + return specs_convertible_result::explicit_conversion; else - return std::integral_constant{}; + return specs_convertible_result::no; } -[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list<>, type_list<>) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<>, type_list<>, type_list<>, + type_list<>) { - return std::integral_constant{}; + return specs_convertible_result::yes; } template -[[nodiscard]] consteval auto are_ingredients_convertible(From, To) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To) { - return decltype(are_ingredients_convertible(type_list_sort{}, - type_list_sort{}, - type_list_sort{}, - type_list_sort{})){}; + return are_ingredients_convertible(type_list_sort{}, + type_list_sort{}, + type_list_sort{}, + type_list_sort{}); } template -[[nodiscard]] consteval auto are_ingredients_convertible(From, To) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To) { - return decltype(are_ingredients_convertible(type_list_sort{}, - type_list_sort{}, - type_list{}, type_list<>{})){}; + return are_ingredients_convertible(type_list_sort{}, + type_list_sort{}, + type_list{}, type_list<>{}); } template -[[nodiscard]] consteval auto are_ingredients_convertible(From, To) +[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To) { - return decltype(are_ingredients_convertible(type_list{}, type_list<>{}, - type_list_sort{}, - type_list_sort{})){}; + return are_ingredients_convertible(type_list{}, type_list<>{}, + type_list_sort{}, + type_list_sort{}); } template -[[nodiscard]] consteval auto convertible_kinds(From from_kind, To to_kind) +[[nodiscard]] consteval specs_convertible_result convertible_kinds(From from_kind, To to_kind) { constexpr auto exploded_kind_result = [](specs_convertible_result res) { using enum specs_convertible_result; return res == no ? no : yes; }; if constexpr ((NamedQuantitySpec && NamedQuantitySpec) || - decltype(get_complexity(from_kind))::value == decltype(get_complexity(to_kind))::value) - return decltype(convertible_impl(from_kind, to_kind)){}; - else if constexpr (decltype(get_complexity(from_kind))::value > decltype(get_complexity(to_kind))::value) - return std::integral_constant(from_kind))::quantity)){}, - to_kind))::value)>{}; + get_complexity(from_kind) == get_complexity(to_kind)) + return convertible_impl(from_kind, to_kind); + else if constexpr (get_complexity(from_kind) > get_complexity(to_kind)) + return exploded_kind_result( + convertible_impl(get_kind_tree_root(explode(from_kind).quantity), to_kind)); else - return std::integral_constant< - specs_convertible_result, - exploded_kind_result(decltype(convertible_impl( - from_kind, decltype(get_kind_tree_root( - decltype(explode(to_kind))::quantity)){}))::value)>{}; + return exploded_kind_result( + convertible_impl(from_kind, get_kind_tree_root(explode(to_kind).quantity))); } template -[[nodiscard]] consteval auto convertible_named(From from, To to) +[[nodiscard]] consteval specs_convertible_result convertible_named(From from, To to) { using enum specs_convertible_result; - if constexpr (decltype(have_common_base(From{}, To{}))::value) { - if constexpr (decltype(is_child_of(From{}, To{}))::value) - return std::integral_constant{}; - else if constexpr (decltype(is_child_of(To{}, From{}))::value) - return std::integral_constant{}; - else if constexpr (get_kind(From{}) == get_kind(To{})) - return std::integral_constant{}; - else - return std::integral_constant{}; + if constexpr (have_common_base(From{}, To{})) { + if constexpr (is_child_of(From{}, To{})) return yes; + if constexpr (is_child_of(To{}, From{})) return explicit_conversion; + if constexpr (get_kind(From{}) == get_kind(To{})) return cast; + return no; } else if constexpr (get_kind(From{}) != get_kind(To{})) - return std::integral_constant{}; - else if constexpr (decltype(get_complexity(From{}))::value != decltype(get_complexity(To{}))::value) { - if constexpr (decltype(get_complexity(From{}))::value > decltype(get_complexity(To{}))::value) - return decltype(convertible_impl(explode(from).quantity, to)){}; + return no; + else if constexpr (get_complexity(From{}) != get_complexity(To{})) { + if constexpr (get_complexity(From{}) > get_complexity(To{})) + return convertible_impl(explode(from).quantity, to); else { - auto res = decltype(explode(to)){}; - return std::integral_constant{}; + auto res = explode(to); + return min(res.result, convertible_impl(from, res.quantity)); } } } template -[[nodiscard]] consteval auto convertible_impl(From from, To to) +[[nodiscard]] consteval specs_convertible_result convertible_impl(From from, To to) { using enum specs_convertible_result; // NOLINTBEGIN(bugprone-branch-clone) if constexpr (From::dimension != To::dimension) - return std::integral_constant{}; + return no; else if constexpr (From{} == To{}) - return std::integral_constant{}; + return yes; else if constexpr (QuantityKindSpec || QuantityKindSpec) { - return decltype(convertible_kinds(decltype(get_kind_tree_root(from)){}, decltype(get_kind_tree_root(to)){})){}; - } else if constexpr (NestedQuantityKindSpecOf && - decltype(get_kind_tree_root(To{})){} == To{}) - return std::integral_constant{}; + return convertible_kinds(get_kind_tree_root(from), get_kind_tree_root(to)); + } else if constexpr (NestedQuantityKindSpecOf && get_kind_tree_root(To{}) == To{}) + return yes; else if constexpr (NamedQuantitySpec && NamedQuantitySpec) { - return decltype(convertible_named(from, to)){}; + return convertible_named(from, to); } else if constexpr (DerivedQuantitySpec && DerivedQuantitySpec) { - return decltype(are_ingredients_convertible(from, to)){}; + return are_ingredients_convertible(from, to); } else if constexpr (DerivedQuantitySpec) { - auto res = decltype(explode(from)){}; + auto res = explode(from); if constexpr (NamedQuantitySpec) - return decltype(convertible_impl(res.quantity, to)){}; + return convertible_impl(res.quantity, to); else if constexpr (requires { to._equation_; }) { - auto eq = decltype(explode_to_equation(to)){}; - return std::integral_constant{}; + auto eq = explode_to_equation(to); + return min(eq.result, convertible_impl(res.quantity, eq.equation)); } else - return decltype(are_ingredients_convertible(from, to)){}; + return are_ingredients_convertible(from, to); } else if constexpr (DerivedQuantitySpec) { - auto res = decltype(explode(to)){}; + auto res = explode(to); if constexpr (NamedQuantitySpec) - return std::integral_constant{}; + return min(res.result, convertible_impl(from, res.quantity)); else if constexpr (requires { from._equation_; }) - return std::integral_constant< - specs_convertible_result, min(res.result, decltype(convertible_impl(from._equation_, res.quantity))::value)>{}; + return min(res.result, convertible_impl(from._equation_, res.quantity)); else - return std::integral_constant{}; - } else - // NOLINTEND(bugprone-branch-clone) - return std::integral_constant{}; + return min(res.result, are_ingredients_convertible(from, to)); + } + // NOLINTEND(bugprone-branch-clone) + return no; } } // namespace detail @@ -1486,19 +1450,19 @@ MP_UNITS_EXPORT_BEGIN template [[nodiscard]] consteval bool implicitly_convertible(From from, To to) { - return decltype(detail::convertible_impl(from, to))::value == detail::specs_convertible_result::yes; + return detail::convertible_impl(from, to) == detail::specs_convertible_result::yes; } template [[nodiscard]] consteval bool explicitly_convertible(From from, To to) { - return decltype(detail::convertible_impl(from, to))::value >= detail::specs_convertible_result::explicit_conversion; + return detail::convertible_impl(from, to) >= detail::specs_convertible_result::explicit_conversion; } template [[nodiscard]] consteval bool castable(From from, To to) { - return decltype(detail::convertible_impl(from, to))::value >= detail::specs_convertible_result::cast; + return detail::convertible_impl(from, to) >= detail::specs_convertible_result::cast; } template @@ -1542,10 +1506,10 @@ template } else if constexpr (defined_as_kind(Q{})) { return q; } else if constexpr (requires { Q::_parent_; }) { - return decltype(get_kind_tree_root(Q::_parent_)){}; + return get_kind_tree_root(Q::_parent_); } else if constexpr (detail::DerivedQuantitySpec) { - return decltype(detail::expr_map(q)){}; + return detail::expr_map(q); } else { // root quantity return q; @@ -1560,15 +1524,15 @@ MP_UNITS_EXPORT_BEGIN template [[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q) { - return kind_of; + return kind_of; } [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q) { return q; } template [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(Q1 q1, Q2 q2) - requires(implicitly_convertible(decltype(get_kind_tree_root(q1)){}, decltype(get_kind_tree_root(q2)){}) || - implicitly_convertible(decltype(get_kind_tree_root(q2)){}, decltype(get_kind_tree_root(q1)){})) + requires(implicitly_convertible(get_kind_tree_root(q1), get_kind_tree_root(q2)) || + implicitly_convertible(get_kind_tree_root(q2), get_kind_tree_root(q1))) { using QQ1 = decltype(detail::remove_kind(q1)); using QQ2 = decltype(detail::remove_kind(q2)); @@ -1594,10 +1558,10 @@ template return q2; else if constexpr (implicitly_convertible(Q2{}, Q1{})) return q1; - else if constexpr (implicitly_convertible(decltype(get_kind_tree_root(Q1{})){}, decltype(get_kind_tree_root(Q2{})){})) - return decltype(get_kind_tree_root(q2)){}; + else if constexpr (implicitly_convertible(get_kind_tree_root(Q1{}), get_kind_tree_root(Q2{}))) + return get_kind_tree_root(q2); else - return decltype(get_kind_tree_root(q1)){}; + return get_kind_tree_root(q1); // NOLINTEND(bugprone-branch-clone) } diff --git a/src/core/include/mp-units/framework/quantity_spec_concepts.h b/src/core/include/mp-units/framework/quantity_spec_concepts.h index 647ac86d..dba816d0 100644 --- a/src/core/include/mp-units/framework/quantity_spec_concepts.h +++ b/src/core/include/mp-units/framework/quantity_spec_concepts.h @@ -126,12 +126,11 @@ MP_UNITS_EXPORT template namespace detail { template -[[nodiscard]] consteval auto is_child_of(Child ch, Parent); +[[nodiscard]] consteval bool is_child_of(Child ch, Parent p); template -concept NestedQuantityKindSpecOf = - QuantitySpec && QuantitySpec && get_kind(From) != get_kind(To) && - decltype(is_child_of(To, get_kind(From)._quantity_spec_))::value; +concept NestedQuantityKindSpecOf = QuantitySpec && QuantitySpec && + get_kind(From) != get_kind(To) && is_child_of(To, get_kind(From)._quantity_spec_); } // namespace detail diff --git a/src/core/include/mp-units/framework/reference.h b/src/core/include/mp-units/framework/reference.h index 345c2384..746abb44 100644 --- a/src/core/include/mp-units/framework/reference.h +++ b/src/core/include/mp-units/framework/reference.h @@ -46,7 +46,7 @@ MP_UNITS_EXPORT_BEGIN [[nodiscard]] consteval QuantitySpec auto get_quantity_spec(AssociatedUnit auto u) { - return decltype(detail::get_associated_quantity(u)){}; + return detail::get_associated_quantity(u); } /** diff --git a/src/core/include/mp-units/framework/unit.h b/src/core/include/mp-units/framework/unit.h index b4fbd126..f5c140a7 100644 --- a/src/core/include/mp-units/framework/unit.h +++ b/src/core/include/mp-units/framework/unit.h @@ -206,7 +206,7 @@ struct named_unit : decltype(U)::_base_type_ { * @tparam QuantitySpec a specification of a quantity to be measured with this unit */ template - requires(!Symbol.empty()) && (QS.dimension == decltype(detail::get_associated_quantity(U))::dimension) + requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension) struct named_unit : decltype(U)::_base_type_ { using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique unit identifier @@ -214,7 +214,7 @@ struct named_unit : decltype(U)::_base_type_ { }; template - requires(!Symbol.empty()) && (QS.dimension == decltype(detail::get_associated_quantity(U))::dimension) + requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension) struct named_unit : decltype(U)::_base_type_ { using _base_type_ = named_unit; // exposition only static constexpr auto symbol = Symbol; ///< Unique unit identifier @@ -339,12 +339,19 @@ struct is_one : std::true_type {}; * @tparam U a unit to use as a `reference_unit` * @tparam M a Magnitude representing an absolute scaling factor of this unit */ -template +template struct canonical_unit { - static constexpr auto mag = M; - static constexpr auto reference_unit = U; + M mag; + U reference_unit; }; +#if MP_UNITS_COMP_CLANG + +template +canonical_unit(M, U) -> canonical_unit; + +#endif + template [[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit&); @@ -360,61 +367,58 @@ template template [[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit_impl&) { - using base = decltype(get_canonical_unit_impl(U{}, U{})); - return canonical_unit{}; + auto base = get_canonical_unit_impl(U{}, U{}); + return canonical_unit{M * base.mag, base.reference_unit}; } template -[[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit&) +[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit&) { - return canonical_unit, T{}>{}; + return canonical_unit{mag<1>, t}; } template [[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit&) { - return decltype(get_canonical_unit_impl(U, U)){}; + return get_canonical_unit_impl(U, U); } template [[nodiscard]] consteval auto get_canonical_unit_impl(const power&, const type_list&) { - using mag = decltype((mp_units::mag<1> * ... * pow(decltype(get_canonical_unit_impl(Us{}, Us{}))::mag))); - using u = decltype((one * ... * pow(decltype(get_canonical_unit_impl(Us{}, Us{}))::reference_unit))); - return canonical_unit{}; + auto mag = (mp_units::mag<1> * ... * pow(get_canonical_unit_impl(Us{}, Us{}).mag)); + auto u = (one * ... * pow(get_canonical_unit_impl(Us{}, Us{}).reference_unit)); + return canonical_unit{mag, u}; } template [[nodiscard]] consteval auto get_canonical_unit_impl(T, const power&) { - using base = decltype(get_canonical_unit_impl(F{}, F{})); - if constexpr (requires { typename decltype(base::reference_unit)::_num_; }) { - using num = - decltype(get_canonical_unit_impl(power{}, typename decltype(base::reference_unit)::_num_{})); - using den = - decltype(get_canonical_unit_impl(power{}, typename decltype(base::reference_unit)::_den_{})); - return canonical_unit(base::mag) * num::mag){} / den::mag){}, - decltype(num::reference_unit / den::reference_unit){}>{}; + auto base = get_canonical_unit_impl(F{}, F{}); + if constexpr (requires { typename decltype(base.reference_unit)::_num_; }) { + auto num = get_canonical_unit_impl(power{}, typename decltype(base.reference_unit)::_num_{}); + auto den = get_canonical_unit_impl(power{}, typename decltype(base.reference_unit)::_den_{}); + return canonical_unit{pow(base.mag) * num.mag / den.mag, num.reference_unit / den.reference_unit}; } else { - return canonical_unit(base::mag)){}, - derived_unit, Num, Den...>>{}>{}; + return canonical_unit{pow(base.mag), + derived_unit>{}}; } } template [[nodiscard]] consteval auto get_canonical_unit_impl(const type_list&) { - using m = decltype((mp_units::mag<1> * ... * decltype(get_canonical_unit_impl(Us{}, Us{}))::mag)); - using u = decltype((one * ... * decltype(get_canonical_unit_impl(Us{}, Us{}))::reference_unit)); - return canonical_unit{}; + auto m = (mp_units::mag<1> * ... * get_canonical_unit_impl(Us{}, Us{}).mag); + auto u = (one * ... * get_canonical_unit_impl(Us{}, Us{}).reference_unit); + return canonical_unit{m, u}; } template [[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit_impl&) { - using num = decltype(get_canonical_unit_impl(typename derived_unit_impl::_num_{})); - using den = decltype(get_canonical_unit_impl(typename derived_unit_impl::_den_{})); - return canonical_unit{}; + auto num = get_canonical_unit_impl(typename derived_unit::_num_{}); + auto den = get_canonical_unit_impl(typename derived_unit::_den_{}); + return canonical_unit{num.mag / den.mag, num.reference_unit / den.reference_unit}; } template @@ -427,10 +431,7 @@ using type_list_of_unit_less = expr_less; // TODO this should really be in the `details` namespace but is used in `chrono.h` (a part of mp_units.systems) // Even though it is not exported, it is visible to the other module via ADL -[[nodiscard]] consteval auto get_canonical_unit(Unit auto u) -{ - return decltype(detail::get_canonical_unit_impl(u, u)){}; -} +[[nodiscard]] consteval auto get_canonical_unit(Unit auto u) { return detail::get_canonical_unit_impl(u, u); } MP_UNITS_EXPORT_BEGIN @@ -456,7 +457,7 @@ template template [[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(M mag, U u) { - return decltype(mag * inverse(u)){}; + return mag * inverse(u); } /** @@ -468,13 +469,13 @@ template [[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(Lhs lhs, Rhs rhs) { if constexpr (detail::is_specialization_of_scaled_unit && detail::is_specialization_of_scaled_unit) - return decltype(Lhs::mag * Rhs::mag){} * decltype(Lhs::reference_unit * Rhs::reference_unit){}; + return (Lhs::mag * Rhs::mag) * (Lhs::reference_unit * Rhs::reference_unit); else if constexpr (detail::is_specialization_of_scaled_unit) - return decltype(Lhs::mag * decltype(Lhs::reference_unit * rhs){}){}; + return Lhs::mag * (Lhs::reference_unit * rhs); else if constexpr (detail::is_specialization_of_scaled_unit) - return decltype(Rhs::mag * decltype(lhs * Rhs::reference_unit){}){}; + return Rhs::mag * (lhs * Rhs::reference_unit); else - return decltype(detail::expr_multiply(lhs, rhs)){}; + return detail::expr_multiply(lhs, rhs); } /** @@ -486,44 +487,39 @@ template [[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(Lhs lhs, Rhs rhs) { if constexpr (detail::is_specialization_of_scaled_unit && detail::is_specialization_of_scaled_unit) - return decltype(Lhs::mag / Rhs::mag){} * decltype(Lhs::reference_unit / Rhs::reference_unit){}; + return (Lhs::mag / Rhs::mag) * (Lhs::reference_unit / Rhs::reference_unit); else if constexpr (detail::is_specialization_of_scaled_unit) - return Lhs::mag * decltype(Lhs::reference_unit / rhs){}; + return Lhs::mag * (Lhs::reference_unit / rhs); else if constexpr (detail::is_specialization_of_scaled_unit) - return decltype(mag<1> / Rhs::mag){} * decltype(lhs / Rhs::reference_unit){}; + return mag<1> / Rhs::mag * (lhs / Rhs::reference_unit); else return detail::expr_divide(lhs, rhs); } -[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto inverse(Unit auto u) { return decltype(one / u){}; } +[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto inverse(Unit auto u) { return one / u; } MP_UNITS_EXPORT_END namespace detail { template -[[nodiscard]] consteval auto have_same_canonical_reference_unit(U1 u1, U2 u2) +[[nodiscard]] consteval bool have_same_canonical_reference_unit(U1 u1, U2 u2) { if constexpr (is_same_v) - return std::true_type{}; - else { - using canonical_lhs = decltype(get_canonical_unit(u1)); - using canonical_rhs = decltype(get_canonical_unit(u2)); - return std::is_same{}; - } + return true; + else + return is_same_v; } } // namespace detail -MP_UNITS_EXPORT template -[[nodiscard]] consteval bool operator==(U1 lhs, U2 rhs) +MP_UNITS_EXPORT [[nodiscard]] consteval bool operator==(Unit auto lhs, Unit auto rhs) { - if constexpr (is_same_v) - return true; - else - return decltype(detail::have_same_canonical_reference_unit(lhs, rhs))::value && - decltype(get_canonical_unit(lhs))::mag == decltype(get_canonical_unit(rhs))::mag; + auto canonical_lhs = get_canonical_unit(lhs); + auto canonical_rhs = get_canonical_unit(rhs); + return detail::have_same_canonical_reference_unit(canonical_lhs.reference_unit, canonical_rhs.reference_unit) && + canonical_lhs.mag == canonical_rhs.mag; } namespace detail { @@ -558,7 +554,7 @@ template else if constexpr (detail::is_specialization_of_scaled_unit) return scaled_unit(U::mag), decltype(pow(U::reference_unit))>{}; else if constexpr (detail::is_specialization_of_derived_unit) - return decltype(detail::expr_pow(u)){}; + return detail::expr_pow(u); else if constexpr (Den == 1) return derived_unit>{}; else @@ -572,7 +568,7 @@ template * * @return Unit The result of computation */ -[[nodiscard]] consteval Unit auto sqrt(Unit auto u) { return decltype(pow<1, 2>(u)){}; } +[[nodiscard]] consteval Unit auto sqrt(Unit auto u) { return pow<1, 2>(u); } /** * @brief Computes the cubic root of a unit @@ -581,7 +577,7 @@ template * * @return Unit The result of computation */ -[[nodiscard]] consteval Unit auto cbrt(Unit auto u) { return decltype(pow<1, 3>(u)){}; } +[[nodiscard]] consteval Unit auto cbrt(Unit auto u) { return pow<1, 3>(u); } /** * @brief Computes the square power of a unit @@ -590,7 +586,7 @@ template * * @return Unit The result of computation */ -[[nodiscard]] consteval Unit auto square(Unit auto u) { return decltype(pow<2>(u)){}; } +[[nodiscard]] consteval Unit auto square(Unit auto u) { return pow<2>(u); } /** * @brief Computes the cubic power of a unit @@ -599,7 +595,7 @@ template * * @return Unit The result of computation */ -[[nodiscard]] consteval Unit auto cubic(Unit auto u) { return decltype(pow<3>(u)){}; } +[[nodiscard]] consteval Unit auto cubic(Unit auto u) { return pow<3>(u); } // common dimensionless units @@ -618,7 +614,7 @@ template if constexpr (is_same_v) return true; else - return decltype(detail::have_same_canonical_reference_unit(from, to))::value; + return detail::have_same_canonical_reference_unit(from, to); } // Common unit @@ -626,7 +622,7 @@ template template [[nodiscard]] consteval Unit auto common_unit(U1 u1, U2 u2) - requires(decltype(detail::have_same_canonical_reference_unit(u1, u2))::value) + requires(detail::have_same_canonical_reference_unit(u1, u2)) { if constexpr (is_same_v) return u1; @@ -637,18 +633,18 @@ template return u2; else // TODO Check if there is a better choice here - return decltype(detail::better_type_name(u1, u2)){}; + return detail::better_type_name(u1, u2); } else { - using canonical_lhs = decltype(get_canonical_unit(U1{})); - using canonical_rhs = decltype(get_canonical_unit(U2{})); + constexpr auto canonical_lhs = get_canonical_unit(U1{}); + constexpr auto canonical_rhs = get_canonical_unit(U2{}); - if constexpr (decltype(is_integral(decltype(canonical_lhs::mag / canonical_rhs::mag){}))::value) + if constexpr (is_integral(canonical_lhs.mag / canonical_rhs.mag)) return u2; - else if constexpr (decltype(is_integral(decltype(canonical_rhs::mag / canonical_lhs::mag){}))::value) + else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag)) return u1; else { - constexpr auto cm = decltype(detail::common_magnitude(canonical_lhs::mag, canonical_rhs::mag)){}; - return scaled_unit>{}; + constexpr auto cm = detail::common_magnitude(canonical_lhs.mag, canonical_rhs.mag); + return scaled_unit{}; } } } @@ -656,7 +652,7 @@ template [[nodiscard]] consteval Unit auto common_unit(Unit auto u1, Unit auto u2, Unit auto u3, Unit auto... rest) requires requires { common_unit(common_unit(u1, u2), u3, rest...); } { - return decltype(common_unit(common_unit(u1, u2), u3, rest...)){}; + return common_unit(common_unit(u1, u2), u3, rest...); } diff --git a/src/core/include/mp-units/framework/unit_concepts.h b/src/core/include/mp-units/framework/unit_concepts.h index 9815db8a..f044e166 100644 --- a/src/core/include/mp-units/framework/unit_concepts.h +++ b/src/core/include/mp-units/framework/unit_concepts.h @@ -191,7 +191,7 @@ concept UnitOf = namespace detail { template -[[nodiscard]] consteval auto have_same_canonical_reference_unit(U1 u1, U2 u2); +[[nodiscard]] consteval bool have_same_canonical_reference_unit(U1 u1, U2 u2); } @@ -204,7 +204,7 @@ template MP_UNITS_EXPORT template concept UnitCompatibleWith = Unit && Unit && QuantitySpec && - (!AssociatedUnit || UnitOf)&&decltype(detail::have_same_canonical_reference_unit(U{}, U2))::value; + (!AssociatedUnit || UnitOf)&&(detail::have_same_canonical_reference_unit(U{}, U2)); } // namespace mp_units diff --git a/src/systems/include/mp-units/systems/si/chrono.h b/src/systems/include/mp-units/systems/si/chrono.h index 3de82704..b52402be 100644 --- a/src/systems/include/mp-units/systems/si/chrono.h +++ b/src/systems/include/mp-units/systems/si/chrono.h @@ -115,8 +115,8 @@ struct quantity_point_like_traits(numerator(m)), get_value(denominator(m))>{}; } @@ -126,8 +126,7 @@ constexpr auto as_ratio(Magnitude auto m) template Q> [[nodiscard]] constexpr auto to_chrono_duration(const Q& q) { - return std::chrono::duration{ - q}; + return std::chrono::duration{q}; } template QP> @@ -136,8 +135,9 @@ template QP> { using clock = MP_UNITS_TYPENAME decltype(QP::absolute_point_origin)::clock; using rep = MP_UNITS_TYPENAME QP::rep; - using ret_type = std::chrono::time_point< - clock, std::chrono::duration>; + using ret_type = + std::chrono::time_point>; return ret_type(to_chrono_duration(qp - qp.absolute_point_origin)); } diff --git a/test/static/prime_test.cpp b/test/static/prime_test.cpp index 9f3502c0..21a7b571 100644 --- a/test/static/prime_test.cpp +++ b/test/static/prime_test.cpp @@ -32,7 +32,7 @@ namespace { template constexpr bool check_primes(std::index_sequence) { - return ((Is < 2 || wheel_factorizer::template is_prime() == is_prime_by_trial_division(Is)) && ...); + return ((Is < 2 || wheel_factorizer::is_prime(Is) == is_prime_by_trial_division(Is)) && ...); } static_assert(check_primes<2>(std::make_index_sequence<122>{})); @@ -45,7 +45,7 @@ static_assert(check_primes<2>(std::make_index_sequence<122>{})); // using numbers of the form (210 * n + 121) as trial divisors, which is a problem if any are prime. For n = 1, we have // a divisor of (210 + 121 = 331), which happens to be prime but will not be used. Thus, (331 * 331 = 109561) is a // composite number which could wrongly appear prime if we skip over 331. -static_assert(wheel_factorizer<4>::is_prime<109'561>() == is_prime_by_trial_division(109'561)); +static_assert(wheel_factorizer<4>::is_prime(109'561) == is_prime_by_trial_division(109'561)); static_assert(wheel_factorizer<1>::coprimes_in_first_wheel.size() == 1); static_assert(wheel_factorizer<2>::coprimes_in_first_wheel.size() == 2); @@ -62,16 +62,16 @@ static_assert(wheel_factorizer<3>::coprimes_in_first_wheel[5] == 19); static_assert(wheel_factorizer<3>::coprimes_in_first_wheel[6] == 23); static_assert(wheel_factorizer<3>::coprimes_in_first_wheel[7] == 29); -static_assert(!wheel_factorizer<1>::is_prime<0>()); -static_assert(!wheel_factorizer<1>::is_prime<1>()); -static_assert(wheel_factorizer<1>::is_prime<2>()); +static_assert(!wheel_factorizer<1>::is_prime(0)); +static_assert(!wheel_factorizer<1>::is_prime(1)); +static_assert(wheel_factorizer<1>::is_prime(2)); -static_assert(!wheel_factorizer<2>::is_prime<0>()); -static_assert(!wheel_factorizer<2>::is_prime<1>()); -static_assert(wheel_factorizer<2>::is_prime<2>()); +static_assert(!wheel_factorizer<2>::is_prime(0)); +static_assert(!wheel_factorizer<2>::is_prime(1)); +static_assert(wheel_factorizer<2>::is_prime(2)); -static_assert(!wheel_factorizer<3>::is_prime<0>()); -static_assert(!wheel_factorizer<3>::is_prime<1>()); -static_assert(wheel_factorizer<3>::is_prime<2>()); +static_assert(!wheel_factorizer<3>::is_prime(0)); +static_assert(!wheel_factorizer<3>::is_prime(1)); +static_assert(wheel_factorizer<3>::is_prime(2)); } // namespace