From 25f986d32cd3f7863a67bca547a2639457d0c343 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 4 Oct 2023 10:00:17 -0600 Subject: [PATCH] fix: MSVC-related fixes and workarounds --- example/measurement.cpp | 8 +- src/core-fmt/include/mp-units/bits/fmt.h | 9 ++- .../include/mp-units/bits/get_common_base.h | 4 +- src/core/include/mp-units/quantity_point.h | 3 +- src/core/include/mp-units/quantity_spec.h | 74 ++++++++++--------- src/core/include/mp-units/reference.h | 17 +++++ src/core/include/mp-units/system_reference.h | 5 ++ src/core/include/mp-units/unit.h | 10 +-- 8 files changed, 78 insertions(+), 52 deletions(-) diff --git a/example/measurement.cpp b/example/measurement.cpp index b67416273..c20d82249 100644 --- a/example/measurement.cpp +++ b/example/measurement.cpp @@ -134,11 +134,11 @@ void example() using namespace mp_units; using namespace mp_units::si::unit_symbols; - const auto a = isq::acceleration(measurement{9.8, 0.1} * (m / s2)); - const auto t = measurement{1.2, 0.1} * s; + const auto acceleration = isq::acceleration(measurement{9.8, 0.1} * (m / s2)); + const auto time = measurement{1.2, 0.1} * s; - const QuantityOf auto v = a * t; - std::cout << a << " * " << t << " = " << v << " = " << v.in(km / h) << '\n'; + const QuantityOf auto velocity = acceleration * time; + std::cout << acceleration << " * " << time << " = " << velocity << " = " << velocity.in(km / h) << '\n'; const auto length = measurement{123., 1.} * m; std::cout << "10 * " << length << " = " << 10 * length << '\n'; diff --git a/src/core-fmt/include/mp-units/bits/fmt.h b/src/core-fmt/include/mp-units/bits/fmt.h index 95ef4549f..973f01ad0 100644 --- a/src/core-fmt/include/mp-units/bits/fmt.h +++ b/src/core-fmt/include/mp-units/bits/fmt.h @@ -103,9 +103,9 @@ struct width_checker { if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative width")); } return static_cast(value); - } else { - MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer")); } + MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer")); + return 0; // should never happen } }; @@ -118,9 +118,9 @@ struct precision_checker { if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative precision")); } return static_cast(value); - } else { - MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("precision is not integer")); } + MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("precision is not integer")); + return 0; // should never happen } }; @@ -230,6 +230,7 @@ template S, typename IDHandler> return begin; } MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("invalid format string")); + return begin; // should never happen } template S, typename IDHandler> diff --git a/src/core/include/mp-units/bits/get_common_base.h b/src/core/include/mp-units/bits/get_common_base.h index 0c232dc19..97ad5fbdd 100644 --- a/src/core/include/mp-units/bits/get_common_base.h +++ b/src/core/include/mp-units/bits/get_common_base.h @@ -58,8 +58,8 @@ template template [[nodiscard]] consteval auto have_common_base(A a, B b) { - constexpr int a_length = hierarchy_path_length(A{}); - constexpr int b_length = hierarchy_path_length(B{}); + 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 have_common_base_in_hierarchy_of_equal_length(hierarchy_path_advance(a), b); else diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 22e37ac90..6cf8308bd 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -142,7 +142,8 @@ class quantity_point { quantity_point& operator=(quantity_point&&) = default; template NewPO> - [[nodiscard]] constexpr QuantityPointOf auto point_for(NewPO new_origin) const + [[nodiscard]] constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(QuantityPointOf) auto point_for( + NewPO new_origin) const { if constexpr (is_same_v>) return *this; diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index b94e476c5..22cc47bb9 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -41,12 +41,12 @@ namespace detail { template requires(!AssociatedUnit) || UnitOf -[[nodiscard]] consteval Reference auto make_reference(QS qs, U u) +[[nodiscard]] consteval Reference auto make_reference(QS, U u) { if constexpr (detail::QuantityKindSpec) return u; else - return reference{}; + return reference{}; } // TODO revise the note in the below comment @@ -494,9 +494,10 @@ template // Operators -[[nodiscard]] consteval QuantitySpec auto operator*(QuantitySpec auto lhs, QuantitySpec auto rhs) +template +[[nodiscard]] consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs) { - return clone_kind_of( + return clone_kind_of( detail::expr_multiply( remove_kind(lhs), remove_kind(rhs))); } @@ -504,15 +505,16 @@ template template [[nodiscard]] consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs) { - return clone_kind_of( + return clone_kind_of( detail::expr_divide( remove_kind(lhs), remove_kind(rhs))); } -[[nodiscard]] consteval QuantitySpec auto operator/(int value, QuantitySpec auto q) +template +[[nodiscard]] consteval QuantitySpec auto operator/(int value, QS qs) { gsl_Expects(value == 1); - return clone_kind_of(detail::expr_invert(q)); + return clone_kind_of(detail::expr_invert(qs)); } [[nodiscard]] consteval QuantitySpec auto operator/(QuantitySpec auto, int) = delete; @@ -554,7 +556,7 @@ template // `2 * one * (2 * one)` should compare to `4 * one` // `2 * rad * (2 * rad)` should compare to `4 * rad^2` // all are dimensionless quantities :-( - if constexpr (Num == 0 || q == dimensionless) + if constexpr (Num == 0 || Q{} == dimensionless) return dimensionless; else if constexpr (ratio{Num, Den} == 1) return q; @@ -779,7 +781,7 @@ template template [[nodiscard]] consteval auto explode(Q q) { - constexpr auto c = get_complexity(q); + constexpr auto c = get_complexity(Q{}); if constexpr (c > Complexity) return explode(q, type_list_sort{}, type_list_sort{}); @@ -790,9 +792,9 @@ template template [[nodiscard]] consteval auto explode(Q q) { - constexpr auto c = get_complexity(q); + constexpr auto c = get_complexity(Q{}); if constexpr (c > Complexity && requires { Q::_equation_; }) { - constexpr auto res = explode_to_equation(q); + constexpr auto res = explode_to_equation(Q{}); return explode(res.equation).common_convertibility_with(res); } else return explode_result{q}; @@ -887,8 +889,8 @@ extract_results(bool, From = {}, To = {}, prepend_rest = {}, Elem = {}) -> extra template [[nodiscard]] consteval auto extract_convertible_quantities(From from, To to) { - constexpr auto qfrom = map_power(from); - constexpr auto qto = 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); @@ -905,8 +907,8 @@ template else return std::tuple{Q{}, ratio{1}}; }; - constexpr auto from_norm = normalize(from); - constexpr auto to_norm = normalize(to); + constexpr auto from_norm = normalize(From{}); + constexpr auto to_norm = normalize(To{}); constexpr auto from_factor = std::get<0>(from_norm); constexpr auto from_exp = std::get<1>(from_norm); constexpr auto to_factor = std::get<0>(to_norm); @@ -1335,11 +1337,11 @@ template if constexpr (From::dimension != To::dimension) return no; - else if constexpr (from == to) + else if constexpr (From{} == To{}) return yes; else if constexpr (QuantityKindSpec || QuantityKindSpec) { - constexpr auto from_kind = get_kind(from); - constexpr auto to_kind = get_kind(to); + constexpr auto from_kind = get_kind(From{}); + constexpr auto to_kind = get_kind(To{}); constexpr auto exploded_kind_result = [](specs_convertible_result res) { using enum specs_convertible_result; return res == no ? no : yes; @@ -1354,21 +1356,21 @@ template else return exploded_kind_result( convertible_impl(from_kind, get_kind(explode(to_kind).quantity))); - } else if constexpr (NestedQuantityKindSpecOf && get_kind(to) == to) + } else if constexpr (NestedQuantityKindSpecOf && get_kind(To{}) == To{}) return yes; else if constexpr (NamedQuantitySpec && NamedQuantitySpec) { - if constexpr (have_common_base(from, to)) { + if constexpr (have_common_base(From{}, To{})) { if (std::derived_from) return yes; else return std::derived_from ? explicit_conversion : (get_kind(from) == get_kind(to) ? cast : no); - } else if constexpr (get_kind(from) != get_kind(to)) + } else if constexpr (get_kind(From{}) != get_kind(To{})) return no; - else if constexpr (get_complexity(from) != get_complexity(to)) { - if constexpr (get_complexity(from) > get_complexity(to)) + 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 { - constexpr auto res = explode(to); + auto res = explode(to); return min(res.result, convertible_impl(from, res.quantity)); } } @@ -1379,7 +1381,7 @@ template if constexpr (NamedQuantitySpec>) return convertible_impl(res.quantity, to); else if constexpr (requires { to._equation_; }) { - constexpr auto eq = explode_to_equation(to); + auto eq = explode_to_equation(to); return min(eq.result, convertible_impl(res.quantity, eq.equation)); } else return are_ingredients_convertible(from, to); @@ -1449,16 +1451,16 @@ template template [[nodiscard]] consteval QuantitySpec auto get_kind(Q q) { - auto defined_as_kind = [](auto qq) { + auto defined_as_kind = [](QQ qq) { if constexpr (requires { detail::defined_as_kind(qq); }) - return detail::defined_as_kind(qq); + return detail::defined_as_kind(QQ{}); else return false; }; if constexpr (detail::QuantityKindSpec) { return remove_kind(q); - } else if constexpr (defined_as_kind(q)) { + } else if constexpr (defined_as_kind(Q{})) { return q; } else if constexpr (requires { Q::_parent_; }) { return get_kind(Q::_parent_); @@ -1481,25 +1483,25 @@ template using QQ2 = std::remove_const_t; if constexpr (is_same_v) return q1; - else if constexpr (detail::NestedQuantityKindSpecOf) + else if constexpr (detail::NestedQuantityKindSpecOf) return remove_kind(q1); - else if constexpr (detail::NestedQuantityKindSpecOf) + else if constexpr (detail::NestedQuantityKindSpecOf) return remove_kind(q2); else if constexpr ((detail::QuantityKindSpec && !detail::QuantityKindSpec) || (detail::IntermediateDerivedQuantitySpec && detail::NamedQuantitySpec && - implicitly_convertible(q1, q2))) + implicitly_convertible(Q1{}, Q2{}))) return q2; else if constexpr ((!detail::QuantityKindSpec && detail::QuantityKindSpec) || (detail::NamedQuantitySpec && detail::IntermediateDerivedQuantitySpec && - implicitly_convertible(q2, q1))) + implicitly_convertible(Q2{}, Q1{}))) return q1; - else if constexpr (detail::have_common_base(q1, q2)) + else if constexpr (detail::have_common_base(Q1{}, Q2{})) return detail::get_common_base(q1, q2); - else if constexpr (implicitly_convertible(q1, q2)) + else if constexpr (implicitly_convertible(Q1{}, Q2{})) return q2; - else if constexpr (implicitly_convertible(q2, q1)) + else if constexpr (implicitly_convertible(Q2{}, Q1{})) return q1; - else if constexpr (implicitly_convertible(get_kind(q1), get_kind(q2))) + else if constexpr (implicitly_convertible(get_kind(Q1{}), get_kind(Q2{}))) return get_kind(q2); else return get_kind(q1); diff --git a/src/core/include/mp-units/reference.h b/src/core/include/mp-units/reference.h index 032c4192a..1633336bd 100644 --- a/src/core/include/mp-units/reference.h +++ b/src/core/include/mp-units/reference.h @@ -22,6 +22,7 @@ #pragma once +#include #include #include #include @@ -73,13 +74,21 @@ struct reference { } template +#if MP_UNITS_COMP_MSVC + [[nodiscard]] friend consteval decltype(reference{}) operator*(reference, U2) +#else [[nodiscard]] friend consteval reference operator*(reference, U2) +#endif { return {}; } template +#if MP_UNITS_COMP_MSVC + [[nodiscard]] friend consteval decltype(reference{}) operator*(U1, reference) +#else [[nodiscard]] friend consteval reference operator*(U1, reference) +#endif { return {}; } @@ -91,13 +100,21 @@ struct reference { } template +#if MP_UNITS_COMP_MSVC + [[nodiscard]] friend consteval decltype(reference{}) operator/(reference, U2) +#else [[nodiscard]] friend consteval reference operator/(reference, U2) +#endif { return {}; } template +#if MP_UNITS_COMP_MSVC + [[nodiscard]] friend consteval decltype(reference{}) operator/(U1, reference) +#else [[nodiscard]] friend consteval reference operator/(U1, reference) +#endif { return {}; } diff --git a/src/core/include/mp-units/system_reference.h b/src/core/include/mp-units/system_reference.h index 32568569a..59f4769c0 100644 --- a/src/core/include/mp-units/system_reference.h +++ b/src/core/include/mp-units/system_reference.h @@ -22,6 +22,7 @@ #pragma once +#include #include #include #include @@ -63,7 +64,11 @@ struct system_reference { template requires(convertible(coherent_unit, U{})) +#if MP_UNITS_COMP_MSVC + [[nodiscard]] constexpr decltype(reference{}) operator[](U) const +#else [[nodiscard]] constexpr reference operator[](U) const +#endif { return {}; } diff --git a/src/core/include/mp-units/unit.h b/src/core/include/mp-units/unit.h index c4343c452..ca3068cff 100644 --- a/src/core/include/mp-units/unit.h +++ b/src/core/include/mp-units/unit.h @@ -354,9 +354,9 @@ template template [[nodiscard]] consteval auto get_canonical_unit_impl(const type_list&) { - auto mag = (mp_units::mag<1> * ... * get_canonical_unit_impl(Us{}, Us{}).mag); + 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{mag, u}; + return canonical_unit{m, u}; } template @@ -402,12 +402,12 @@ using type_list_of_unit_less = expr_less; * Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned. */ template -[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M mag, const U u) +[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M, const U u) { - if constexpr (mag == mp_units::mag<1>) + if constexpr (std::is_same_v)>>) return u; else - return scaled_unit{}; + return scaled_unit{}; } [[nodiscard]] consteval Unit auto operator*(Unit auto, Magnitude auto) = delete;