Skip to content

Commit

Permalink
fix: MSVC-related fixes and workarounds
Browse files Browse the repository at this point in the history
  • Loading branch information
mpusz committed Oct 4, 2023
1 parent 2281be0 commit 25f986d
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 52 deletions.
8 changes: 4 additions & 4 deletions example/measurement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<isq::velocity> auto v = a * t;
std::cout << a << " * " << t << " = " << v << " = " << v.in(km / h) << '\n';
const QuantityOf<isq::velocity> 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';
Expand Down
9 changes: 5 additions & 4 deletions src/core-fmt/include/mp-units/bits/fmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ struct width_checker {
if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative width"));
}
return static_cast<unsigned long long>(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
}
};

Expand All @@ -118,9 +118,9 @@ struct precision_checker {
if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative precision"));
}
return static_cast<unsigned long long>(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
}
};

Expand Down Expand Up @@ -230,6 +230,7 @@ template<std::input_iterator It, std::sentinel_for<It> S, typename IDHandler>
return begin;
}
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("invalid format string"));
return begin; // should never happen
}

template<std::input_iterator It, std::sentinel_for<It> S, typename IDHandler>
Expand Down
4 changes: 2 additions & 2 deletions src/core/include/mp-units/bits/get_common_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ template<QuantitySpec A, QuantitySpec B>
template<QuantitySpec A, QuantitySpec B>
[[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_length - b_length>(a), b);
else
Expand Down
3 changes: 2 additions & 1 deletion src/core/include/mp-units/quantity_point.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ class quantity_point {
quantity_point& operator=(quantity_point&&) = default;

template<PointOriginFor<quantity_spec> NewPO>
[[nodiscard]] constexpr QuantityPointOf<NewPO{}> auto point_for(NewPO new_origin) const
[[nodiscard]] constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(QuantityPointOf<NewPO{}>) auto point_for(
NewPO new_origin) const
{
if constexpr (is_same_v<NewPO, std::remove_const_t<decltype(point_origin)>>)
return *this;
Expand Down
74 changes: 38 additions & 36 deletions src/core/include/mp-units/quantity_spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ namespace detail {

template<QuantitySpec QS, Unit U>
requires(!AssociatedUnit<U>) || UnitOf<U, QS{}>
[[nodiscard]] consteval Reference auto make_reference(QS qs, U u)
[[nodiscard]] consteval Reference auto make_reference(QS, U u)
{
if constexpr (detail::QuantityKindSpec<QS>)
return u;
else
return reference<qs, u>{};
return reference<QS{}, U{}>{};
}

// TODO revise the note in the below comment
Expand Down Expand Up @@ -494,25 +494,27 @@ template<QuantitySpec auto... From, QuantitySpec Q>

// Operators

[[nodiscard]] consteval QuantitySpec auto operator*(QuantitySpec auto lhs, QuantitySpec auto rhs)
template<QuantitySpec Lhs, QuantitySpec Rhs>
[[nodiscard]] consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs)
{
return clone_kind_of<lhs, rhs>(
return clone_kind_of<Lhs{}, Rhs{}>(
detail::expr_multiply<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
remove_kind(lhs), remove_kind(rhs)));
}

template<QuantitySpec Lhs, QuantitySpec Rhs>
[[nodiscard]] consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs)
{
return clone_kind_of<lhs, rhs>(
return clone_kind_of<Lhs{}, Rhs{}>(
detail::expr_divide<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
remove_kind(lhs), remove_kind(rhs)));
}

[[nodiscard]] consteval QuantitySpec auto operator/(int value, QuantitySpec auto q)
template<QuantitySpec QS>
[[nodiscard]] consteval QuantitySpec auto operator/(int value, QS qs)
{
gsl_Expects(value == 1);
return clone_kind_of<q>(detail::expr_invert<derived_quantity_spec, struct dimensionless>(q));
return clone_kind_of<QS{}>(detail::expr_invert<derived_quantity_spec, struct dimensionless>(qs));
}

[[nodiscard]] consteval QuantitySpec auto operator/(QuantitySpec auto, int) = delete;
Expand Down Expand Up @@ -554,7 +556,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
// `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;
Expand Down Expand Up @@ -779,7 +781,7 @@ template<int Complexity, QuantitySpec Q>
template<int Complexity, IntermediateDerivedQuantitySpec Q>
[[nodiscard]] consteval auto explode(Q q)
{
constexpr auto c = get_complexity(q);
constexpr auto c = get_complexity(Q{});
if constexpr (c > Complexity)
return explode<Complexity>(q, type_list_sort<typename Q::_num_, type_list_of_ingredients_less>{},
type_list_sort<typename Q::_den_, type_list_of_ingredients_less>{});
Expand All @@ -790,9 +792,9 @@ template<int Complexity, IntermediateDerivedQuantitySpec Q>
template<int Complexity, NamedQuantitySpec Q>
[[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<Complexity>(res.equation).common_convertibility_with(res);
} else
return explode_result{q};
Expand Down Expand Up @@ -887,8 +889,8 @@ extract_results(bool, From = {}, To = {}, prepend_rest = {}, Elem = {}) -> extra
template<typename From, typename To>
[[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<From> && is_specialization_of_power<To>) {
constexpr auto cr = common_ratio(From::exponent, To::exponent);
Expand All @@ -905,8 +907,8 @@ template<typename From, typename To>
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);
Expand Down Expand Up @@ -1335,11 +1337,11 @@ template<QuantitySpec From, QuantitySpec To>

if constexpr (From::dimension != To::dimension)
return no;
else if constexpr (from == to)
else if constexpr (From{} == To{})
return yes;
else if constexpr (QuantityKindSpec<From> || QuantityKindSpec<To>) {
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;
Expand All @@ -1354,21 +1356,21 @@ template<QuantitySpec From, QuantitySpec To>
else
return exploded_kind_result(
convertible_impl(from_kind, get_kind(explode<get_complexity(from_kind)>(to_kind).quantity)));
} else if constexpr (NestedQuantityKindSpecOf<get_kind(to), from> && get_kind(to) == to)
} else if constexpr (NestedQuantityKindSpecOf<get_kind(To{}), from> && get_kind(To{}) == To{})
return yes;
else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) {
if constexpr (have_common_base(from, to)) {
if constexpr (have_common_base(From{}, To{})) {
if (std::derived_from<From, To>)
return yes;
else
return std::derived_from<To, 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<get_complexity(to)>(from).quantity, to);
else {
constexpr auto res = explode<get_complexity(from)>(to);
auto res = explode<get_complexity(from)>(to);
return min(res.result, convertible_impl(from, res.quantity));
}
}
Expand All @@ -1379,7 +1381,7 @@ template<QuantitySpec From, QuantitySpec To>
if constexpr (NamedQuantitySpec<std::remove_const_t<decltype(res.quantity)>>)
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);
Expand Down Expand Up @@ -1449,16 +1451,16 @@ template<QuantitySpec Q>
template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q)
{
auto defined_as_kind = [](auto qq) {
auto defined_as_kind = []<typename QQ>(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<Q>) {
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_);
Expand All @@ -1481,25 +1483,25 @@ template<QuantitySpec Q1, QuantitySpec Q2>
using QQ2 = std::remove_const_t<decltype(remove_kind(q2))>;
if constexpr (is_same_v<Q1, Q2>)
return q1;
else if constexpr (detail::NestedQuantityKindSpecOf<q1, q2>)
else if constexpr (detail::NestedQuantityKindSpecOf<Q1{}, Q2{}>)
return remove_kind(q1);
else if constexpr (detail::NestedQuantityKindSpecOf<q2, q1>)
else if constexpr (detail::NestedQuantityKindSpecOf<Q2{}, Q1{}>)
return remove_kind(q2);
else if constexpr ((detail::QuantityKindSpec<Q1> && !detail::QuantityKindSpec<Q2>) ||
(detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> &&
implicitly_convertible(q1, q2)))
implicitly_convertible(Q1{}, Q2{})))
return q2;
else if constexpr ((!detail::QuantityKindSpec<Q1> && detail::QuantityKindSpec<Q2>) ||
(detail::NamedQuantitySpec<QQ1> && detail::IntermediateDerivedQuantitySpec<QQ2> &&
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);
Expand Down
17 changes: 17 additions & 0 deletions src/core/include/mp-units/reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#pragma once

#include <mp-units/bits/external/hacks.h>
#include <mp-units/bits/get_associated_quantity.h>
#include <mp-units/bits/quantity_concepts.h>
#include <mp-units/bits/reference_concepts.h>
Expand Down Expand Up @@ -73,13 +74,21 @@ struct reference {
}

template<AssociatedUnit U2>
#if MP_UNITS_COMP_MSVC
[[nodiscard]] friend consteval decltype(reference<Q * get_quantity_spec(U2{}), U * U2{}>{}) operator*(reference, U2)
#else
[[nodiscard]] friend consteval reference<Q * get_quantity_spec(U2{}), U * U2{}> operator*(reference, U2)
#endif
{
return {};
}

template<AssociatedUnit U1>
#if MP_UNITS_COMP_MSVC
[[nodiscard]] friend consteval decltype(reference<get_quantity_spec(U1{}) * Q, U1{} * U>{}) operator*(U1, reference)
#else
[[nodiscard]] friend consteval reference<get_quantity_spec(U1{}) * Q, U1{} * U> operator*(U1, reference)
#endif
{
return {};
}
Expand All @@ -91,13 +100,21 @@ struct reference {
}

template<AssociatedUnit U2>
#if MP_UNITS_COMP_MSVC
[[nodiscard]] friend consteval decltype(reference<Q / get_quantity_spec(U2{}), U / U2{}>{}) operator/(reference, U2)
#else
[[nodiscard]] friend consteval reference<Q / get_quantity_spec(U2{}), U / U2{}> operator/(reference, U2)
#endif
{
return {};
}

template<AssociatedUnit U1>
#if MP_UNITS_COMP_MSVC
[[nodiscard]] friend consteval decltype(reference<get_quantity_spec(U1{}) / Q, U1{} / U>{}) operator/(U1, reference)
#else
[[nodiscard]] friend consteval reference<get_quantity_spec(U1{}) / Q, U1{} / U> operator/(U1, reference)
#endif
{
return {};
}
Expand Down
5 changes: 5 additions & 0 deletions src/core/include/mp-units/system_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#pragma once

#include <mp-units/bits/external/hacks.h>
#include <mp-units/quantity_spec.h>
#include <mp-units/reference.h>
#include <mp-units/unit.h>
Expand Down Expand Up @@ -63,7 +64,11 @@ struct system_reference {

template<Unit U>
requires(convertible(coherent_unit, U{}))
#if MP_UNITS_COMP_MSVC
[[nodiscard]] constexpr decltype(reference<quantity_spec, U{}>{}) operator[](U) const
#else
[[nodiscard]] constexpr reference<quantity_spec, U{}> operator[](U) const
#endif
{
return {};
}
Expand Down
10 changes: 5 additions & 5 deletions src/core/include/mp-units/unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,9 @@ template<typename T, typename F, int Num, int... Den>
template<typename... Us>
[[nodiscard]] consteval auto get_canonical_unit_impl(const type_list<Us...>&)
{
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<Unit T, typename... Expr>
Expand Down Expand Up @@ -402,12 +402,12 @@ using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
* Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned.
*/
template<Magnitude M, Unit U>
[[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<M, std::remove_cvref_t<decltype(mp_units::mag<1>)>>)
return u;
else
return scaled_unit<mag, U>{};
return scaled_unit<M{}, U>{};
}

[[nodiscard]] consteval Unit auto operator*(Unit auto, Magnitude auto) = delete;
Expand Down

0 comments on commit 25f986d

Please sign in to comment.