diff --git a/src/core/include/mp-units/framework/quantity_spec.h b/src/core/include/mp-units/framework/quantity_spec.h index a40d631e..04808137 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 && (detail::get_kind_tree_root(Q{}) == Q{}) + requires detail::QuantitySpecWithNoSpecifiers && (decltype(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 && (detail::get_kind_tree_root(Q{}) == Q{}) + requires detail::QuantitySpecWithNoSpecifiers && (decltype(detail::get_kind_tree_root(Q{})){} == Q{}) #else template - requires(detail::get_kind_tree_root(Q{}) == Q{}) + requires(decltype(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(detail::get_kind_tree_root(Q) == Q) + requires(decltype(detail::get_kind_tree_root(Q)){} == Q) inline constexpr kind_of_ kind_of; namespace detail { @@ -820,71 +820,59 @@ template template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list num_from, - type_list den_from, - type_list num_to, - type_list den_to); +[[nodiscard]] consteval auto are_ingredients_convertible(type_list num_from, + type_list den_from, + type_list num_to, + type_list den_to); template -[[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); template -[[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); template -[[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); template -[[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<>); template -[[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<>); template -[[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); template -[[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<>); template -[[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); template -[[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<>); template -[[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<>); template -[[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<>); template -[[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<>); +[[nodiscard]] consteval auto are_ingredients_convertible(type_list<>, type_list<>, type_list<>, type_list<>); enum class prepend_rest : std::int8_t { no, first, second }; @@ -946,49 +934,63 @@ template enum class process_entities : std::int8_t { numerators, denominators, from, to }; template -[[nodiscard]] consteval specs_convertible_result process_num_den(NumFrom num_from, DenFrom den_from, NumTo num_to, - DenTo den_to) +[[nodiscard]] consteval auto process_num_den(NumFrom num_from, DenFrom den_from, NumTo num_to, DenTo den_to) { - constexpr auto res = convertible_impl(Ext.from, Ext.to); + constexpr auto res = decltype(convertible_impl(Ext.from, Ext.to))::value; if constexpr (Ext.prepend == prepend_rest::no) - return min(res, are_ingredients_convertible(num_from, den_from, num_to, den_to)); + return std::integral_constant{}; else { using elem = decltype(Ext.elem); if constexpr (Entities == process_entities::numerators) { if constexpr (Ext.prepend == prepend_rest::first) - return min(res, are_ingredients_convertible(type_list_push_front{}, den_from, num_to, den_to)); + return std::integral_constant{}, + den_from, num_to, den_to))::value)>{}; else - return min(res, are_ingredients_convertible(num_from, den_from, type_list_push_front{}, den_to)); + return std::integral_constant{}, + den_to))::value)>{}; } else { if constexpr (Ext.prepend == prepend_rest::first) - return min(res, are_ingredients_convertible(num_from, type_list_push_front{}, num_to, den_to)); + return std::integral_constant{}, num_to, + den_to))::value)>{}; else - return min(res, are_ingredients_convertible(num_from, den_from, num_to, type_list_push_front{})); + return std::integral_constant{}))::value)>{}; } } } template -[[nodiscard]] consteval specs_convertible_result process_extracted(NumFrom num_from, DenFrom den_from, NumTo num_to, - DenTo den_to) +[[nodiscard]] consteval auto 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 process_num_den(num_from, den_from, num_to, den_to); + return decltype(process_num_den(num_from, den_from, num_to, den_to)){}; } else { if constexpr (Ext.prepend == prepend_rest::no) - return are_ingredients_convertible(num_from, den_from, num_to, den_to); + return decltype(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 are_ingredients_convertible(type_list_push_front{}, den_from, num_to, den_to); + return decltype(are_ingredients_convertible(type_list_push_front{}, den_from, num_to, + den_to)){}; else - return are_ingredients_convertible(num_from, type_list_push_front{}, num_to, den_to); + return decltype(are_ingredients_convertible(num_from, type_list_push_front{}, num_to, + den_to)){}; } else { if constexpr (Ext.prepend == prepend_rest::first) - return are_ingredients_convertible(num_from, den_from, type_list_push_front{}, den_to); + return decltype(are_ingredients_convertible(num_from, den_from, type_list_push_front{}, + den_to)){}; else - return are_ingredients_convertible(num_from, den_from, num_to, type_list_push_front{}); + return decltype(are_ingredients_convertible(num_from, den_from, num_to, + type_list_push_front{})){}; } } } @@ -996,23 +998,23 @@ template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list num_from, - type_list den_from, - type_list num_to, - type_list den_to) +[[nodiscard]] consteval auto 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 process_extracted(type_list{}, den_from, - type_list{}, den_to); + return decltype(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 process_extracted(num_from, type_list{}, num_to, - type_list{}); + return decltype(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 process_extracted(type_list{}, type_list{}, num_to, - den_to); + return decltype(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 process_extracted(num_from, den_from, type_list{}, - type_list{}); + return decltype(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; @@ -1021,45 +1023,52 @@ template 1) { if constexpr (num_from_compl == max_compl) { - 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{}))); + 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{}))){}){})){}; } else if constexpr (den_from_compl == max_compl) { - 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{}))); + 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{}))){}){})){}; } else if constexpr (num_to_compl == max_compl) { - 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{})))); + 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)>{}; } else { - 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{})))); + 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)>{}; } - } + } else + return std::integral_constant{}; } - return specs_convertible_result::no; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<> num_from, - type_list den_from, - type_list num_to, - type_list) +[[nodiscard]] consteval auto 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 process_extracted(num_from, type_list{}, num_to, - type_list{}); + return decltype(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 process_extracted(num_from, den_from, type_list{}, - type_list{}); + return decltype(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; @@ -1067,38 +1076,46 @@ template 1) { if constexpr (den_from_compl == max_compl) { - 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{}))); + 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{}))){}){})){}; } else if constexpr (num_to_compl == max_compl) { - 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{})))); + 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)>{}; } else { - 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{})))); + 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)>{}; } - } + } else + return std::integral_constant{}; } - return specs_convertible_result::no; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list num_from, - type_list<> den_from, - type_list, - type_list den_to) +[[nodiscard]] consteval auto 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 process_extracted(type_list{}, den_from, - type_list{}, den_to); + return decltype(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 process_extracted(num_from, den_from, type_list{}, - type_list{}); + return decltype(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; @@ -1106,39 +1123,44 @@ template 1) { if constexpr (num_from_compl == max_compl) { - 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{}))); + 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{}))){}){})){}; } else if constexpr (num_to_compl == max_compl) { - 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{})))); + 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)>{}; } else { - 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{})))); + 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)>{}; } - } + } else + return std::integral_constant{}; } - return specs_convertible_result::no; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list num_from, - type_list, - type_list<> num_to, - type_list den_to) +[[nodiscard]] consteval auto 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 process_extracted(num_from, type_list{}, num_to, - type_list{}); + return decltype(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 process_extracted(type_list{}, type_list{}, num_to, - den_to); + return decltype(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; @@ -1146,39 +1168,44 @@ template 1) { if constexpr (num_from_compl == max_compl) { - 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{}))); + 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{}))){}){})){}; } else if constexpr (den_from_compl == max_compl) { - 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{}))); + 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{}))){}){})){}; } else { - 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{})))); + 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)>{}; } - } + } else + return std::integral_constant{}; } - return specs_convertible_result::no; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, - type_list den_from, - type_list num_to, - type_list<> den_to) +[[nodiscard]] consteval auto 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 process_extracted(type_list{}, den_from, - type_list{}, den_to); + return decltype(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 process_extracted(type_list{}, type_list{}, num_to, - den_to); + return decltype(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; @@ -1186,176 +1213,178 @@ template 1) { if constexpr (num_from_compl == max_compl) { - 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{}))); + 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{}))){})){}; } else if constexpr (den_from_compl == max_compl) { - 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{}))); + 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{}))){})){}; } else { - 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{})))); + 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)>{}; } - } + } else + return std::integral_constant{}; } - return specs_convertible_result::no; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list, - type_list<> den_from, - type_list, - type_list<> den_to) +[[nodiscard]] consteval auto 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 process_extracted(type_list{}, den_from, - type_list{}, den_to); + return decltype(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 max_compl = max(num_from_compl, num_to_compl); if constexpr (max_compl > 1) { if constexpr (num_from_compl == max_compl) { - constexpr auto res = explode_to_equation(NumFrom{}); - return convertible_impl((res.equation * ... * map_power(NumsFrom{})), - (map_power(NumTo{}) * ... * map_power(NumsTo{}))); + 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{}))){})){}; } else { - constexpr auto res = explode_to_equation(NumTo{}); - return min(res.result, convertible_impl((map_power(NumFrom{}) * ... * map_power(NumsFrom{})), - (res.equation * ... * map_power(NumsTo{})))); + 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)>{}; } - } + } else + return std::integral_constant{}; } - return specs_convertible_result::no; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(type_list<> num_from, - type_list, - type_list<> num_to, - type_list) +[[nodiscard]] consteval auto 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 process_extracted(num_from, type_list{}, num_to, - type_list{}); + return decltype(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 max_compl = max(den_from_compl, den_to_compl); if constexpr (max_compl > 1) { if constexpr (den_from_compl == max_compl) { - constexpr auto res = explode_to_equation(DenFrom{}); - return convertible_impl(dimensionless / (res.equation * ... * map_power(DensFrom{})), - dimensionless / (map_power(DenTo{}) * ... * map_power(DensTo{}))); + 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{}))){}){})){}; } else { - 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{})))); + 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)>{}; } - } + } else + return std::integral_constant{}; } - return specs_convertible_result::no; } template -[[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<>) { - if constexpr (((... * map_power(NumsFrom{})) / (... * map_power(DensFrom{}))).dimension == dimension_one) - return specs_convertible_result::yes; + if constexpr (decltype(decltype((... * map_power(NumsFrom{}))){} / + decltype((... * map_power(DensFrom{}))){})::dimension == dimension_one) + return std::integral_constant{}; else - return specs_convertible_result::no; + return std::integral_constant{}; } template -[[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) { - if constexpr (((... * map_power(NumsTo{})) / (... * map_power(DensTo{}))).dimension == dimension_one) - return specs_convertible_result::explicit_conversion; + if constexpr (decltype(decltype((... * map_power(NumsTo{}))){} / + decltype((... * map_power(DensTo{}))){})::dimension == dimension_one) + return std::integral_constant{}; else - return specs_convertible_result::no; + return std::integral_constant{}; } template -[[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<>) { - if constexpr ((... * map_power(NumsFrom{})).dimension == dimension_one) - return specs_convertible_result::yes; + if constexpr (decltype((... * map_power(NumsFrom{})))::dimension == dimension_one) + return std::integral_constant{}; else - return specs_convertible_result::no; + return std::integral_constant{}; } template -[[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<>) { - if constexpr ((... * map_power(DensFrom{})).dimension == dimension_one) - return specs_convertible_result::yes; + if constexpr (decltype((... * map_power(DensFrom{})))::dimension == dimension_one) + return std::integral_constant{}; else - return specs_convertible_result::no; + return std::integral_constant{}; } template -[[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<>) { - if constexpr ((... * map_power(NumsTo{})).dimension == dimension_one) - return specs_convertible_result::explicit_conversion; + if constexpr (decltype((... * map_power(NumsTo{})))::dimension == dimension_one) + return std::integral_constant{}; else - return specs_convertible_result::no; + return std::integral_constant{}; } template -[[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) { - if constexpr ((... * map_power(DensTo{})).dimension == dimension_one) - return specs_convertible_result::explicit_conversion; + if constexpr (decltype((... * map_power(DensTo{})))::dimension == dimension_one) + return std::integral_constant{}; else - return specs_convertible_result::no; + return std::integral_constant{}; } -[[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<>) { - return specs_convertible_result::yes; + return std::integral_constant{}; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To) +[[nodiscard]] consteval auto are_ingredients_convertible(From, To) { - return are_ingredients_convertible(type_list_sort{}, - type_list_sort{}, - type_list_sort{}, - type_list_sort{}); + return decltype(are_ingredients_convertible(type_list_sort{}, + type_list_sort{}, + type_list_sort{}, + type_list_sort{})){}; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To) +[[nodiscard]] consteval auto are_ingredients_convertible(From, To) { - return are_ingredients_convertible(type_list_sort{}, - type_list_sort{}, - type_list{}, type_list<>{}); + return decltype(are_ingredients_convertible(type_list_sort{}, + type_list_sort{}, + type_list{}, type_list<>{})){}; } template -[[nodiscard]] consteval specs_convertible_result are_ingredients_convertible(From, To) +[[nodiscard]] consteval auto are_ingredients_convertible(From, To) { - return are_ingredients_convertible(type_list{}, type_list<>{}, - type_list_sort{}, - type_list_sort{}); + return decltype(are_ingredients_convertible(type_list{}, type_list<>{}, + type_list_sort{}, + type_list_sort{})){}; } template -[[nodiscard]] consteval specs_convertible_result convertible_kinds(From from_kind, To to_kind) +[[nodiscard]] consteval auto convertible_kinds(From from_kind, To to_kind) { constexpr auto exploded_kind_result = [](specs_convertible_result res) { using enum specs_convertible_result; @@ -1363,75 +1392,91 @@ template }; if constexpr ((NamedQuantitySpec && NamedQuantitySpec) || decltype(get_complexity(from_kind))::value == decltype(get_complexity(to_kind))::value) - return convertible_impl(from_kind, to_kind); + return decltype(convertible_impl(from_kind, to_kind)){}; else if constexpr (decltype(get_complexity(from_kind))::value > decltype(get_complexity(to_kind))::value) - return exploded_kind_result(convertible_impl( - get_kind_tree_root(explode(from_kind).quantity), to_kind)); + return std::integral_constant(from_kind))::quantity)){}, + to_kind))::value)>{}; else - return exploded_kind_result(convertible_impl( - from_kind, get_kind_tree_root(explode(to_kind).quantity))); + 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)>{}; } template -[[nodiscard]] consteval specs_convertible_result convertible_named(From from, To to) +[[nodiscard]] consteval auto convertible_named(From from, To to) { using enum specs_convertible_result; - if constexpr (have_common_base(From{}, To{})) { - if constexpr (decltype(is_child_of(From{}, To{}))::value) return yes; - if constexpr (decltype(is_child_of(To{}, From{}))::value) return explicit_conversion; - if constexpr (get_kind(From{}) == get_kind(To{})) return cast; - return no; + 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{}; } else if constexpr (get_kind(From{}) != get_kind(To{})) - return no; + 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 convertible_impl(explode(from).quantity, to); + return decltype(convertible_impl(explode(from).quantity, to)){}; else { - auto res = explode(to); - return min(res.result, convertible_impl(from, res.quantity)); + auto res = decltype(explode(to)){}; + return std::integral_constant{}; } } } template -[[nodiscard]] consteval specs_convertible_result convertible_impl(From from, To to) +[[nodiscard]] consteval auto convertible_impl(From from, To to) { using enum specs_convertible_result; // NOLINTBEGIN(bugprone-branch-clone) if constexpr (From::dimension != To::dimension) - return no; + return std::integral_constant{}; else if constexpr (From{} == To{}) - return yes; + return std::integral_constant{}; else if constexpr (QuantityKindSpec || QuantityKindSpec) { - 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; + 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{}; else if constexpr (NamedQuantitySpec && NamedQuantitySpec) { - return convertible_named(from, to); + return decltype(convertible_named(from, to)){}; } else if constexpr (DerivedQuantitySpec && DerivedQuantitySpec) { - return are_ingredients_convertible(from, to); + return decltype(are_ingredients_convertible(from, to)){}; } else if constexpr (DerivedQuantitySpec) { - auto res = explode(from); + auto res = decltype(explode(from)){}; if constexpr (NamedQuantitySpec) - return convertible_impl(res.quantity, to); + return decltype(convertible_impl(res.quantity, to)){}; else if constexpr (requires { to._equation_; }) { - auto eq = explode_to_equation(to); - return min(eq.result, convertible_impl(res.quantity, eq.equation)); + auto eq = decltype(explode_to_equation(to)){}; + return std::integral_constant{}; } else - return are_ingredients_convertible(from, to); + return decltype(are_ingredients_convertible(from, to)){}; } else if constexpr (DerivedQuantitySpec) { - auto res = explode(to); + auto res = decltype(explode(to)){}; if constexpr (NamedQuantitySpec) - return min(res.result, convertible_impl(from, res.quantity)); + return std::integral_constant{}; else if constexpr (requires { from._equation_; }) - return min(res.result, convertible_impl(from._equation_, res.quantity)); + return std::integral_constant< + specs_convertible_result, min(res.result, decltype(convertible_impl(from._equation_, res.quantity))::value)>{}; else - return min(res.result, are_ingredients_convertible(from, to)); - } - // NOLINTEND(bugprone-branch-clone) - return no; + return std::integral_constant{}; + } else + // NOLINTEND(bugprone-branch-clone) + return std::integral_constant{}; } } // namespace detail @@ -1441,19 +1486,19 @@ MP_UNITS_EXPORT_BEGIN template [[nodiscard]] consteval bool implicitly_convertible(From from, To to) { - return detail::convertible_impl(from, to) == detail::specs_convertible_result::yes; + return decltype(detail::convertible_impl(from, to))::value == detail::specs_convertible_result::yes; } template [[nodiscard]] consteval bool explicitly_convertible(From from, To to) { - return detail::convertible_impl(from, to) >= detail::specs_convertible_result::explicit_conversion; + return decltype(detail::convertible_impl(from, to))::value >= detail::specs_convertible_result::explicit_conversion; } template [[nodiscard]] consteval bool castable(From from, To to) { - return detail::convertible_impl(from, to) >= detail::specs_convertible_result::cast; + return decltype(detail::convertible_impl(from, to))::value >= detail::specs_convertible_result::cast; } template @@ -1497,7 +1542,7 @@ template } else if constexpr (defined_as_kind(Q{})) { return q; } else if constexpr (requires { Q::_parent_; }) { - return get_kind_tree_root(Q::_parent_); + return decltype(get_kind_tree_root(Q::_parent_)){}; } else if constexpr (detail::DerivedQuantitySpec) { return decltype(detail::expr_map(q)){}; @@ -1515,15 +1560,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(get_kind_tree_root(q1), get_kind_tree_root(q2)) || - implicitly_convertible(get_kind_tree_root(q2), get_kind_tree_root(q1))) + 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)){})) { using QQ1 = decltype(detail::remove_kind(q1)); using QQ2 = decltype(detail::remove_kind(q2)); @@ -1549,10 +1594,10 @@ template return q2; else if constexpr (implicitly_convertible(Q2{}, Q1{})) return q1; - else if constexpr (implicitly_convertible(get_kind_tree_root(Q1{}), get_kind_tree_root(Q2{}))) - return get_kind_tree_root(q2); + 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 - return get_kind_tree_root(q1); + return decltype(get_kind_tree_root(q1)){}; // NOLINTEND(bugprone-branch-clone) }