mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-05 05:04:27 +02:00
feat: common_reference
, common_dimension
, and common_units
now take variadic list of arguments
This commit is contained in:
@@ -328,6 +328,25 @@ template<Dimension D1, Dimension D2>
|
|||||||
return std::derived_from<D1, D2> || std::derived_from<D2, D1>;
|
return std::derived_from<D1, D2> || std::derived_from<D2, D1>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] consteval auto common_dimension(Dimension auto d) { return d; }
|
||||||
|
|
||||||
|
template<Dimension D1, Dimension D2>
|
||||||
|
[[nodiscard]] consteval auto common_dimension(D1 d1, D2 d2)
|
||||||
|
requires(interconvertible(d1, d2))
|
||||||
|
{
|
||||||
|
if constexpr (std::derived_from<D1, D2>)
|
||||||
|
return d1;
|
||||||
|
else
|
||||||
|
return d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] consteval auto common_dimension(Dimension auto d1, Dimension auto d2, Dimension auto d3,
|
||||||
|
Dimension auto... rest)
|
||||||
|
requires requires { common_dimension(common_dimension(d1, d2), d3, rest...); }
|
||||||
|
{
|
||||||
|
return common_dimension(common_dimension(d1, d2), d3, rest...);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Computes the value of a dimension raised to the `Num/Den` power
|
* @brief Computes the value of a dimension raised to the `Num/Den` power
|
||||||
*
|
*
|
||||||
@@ -384,16 +403,6 @@ template<Unit auto U, Dimension auto Dim>
|
|||||||
requires requires { detail::get_dimension_for(U); } && (interconvertible(Dim, detail::get_dimension_for(U)))
|
requires requires { detail::get_dimension_for(U); } && (interconvertible(Dim, detail::get_dimension_for(U)))
|
||||||
inline constexpr bool is_valid_unit_for_dimension<U, Dim> = true;
|
inline constexpr bool is_valid_unit_for_dimension<U, Dim> = true;
|
||||||
|
|
||||||
template<Dimension D1, Dimension D2>
|
|
||||||
[[nodiscard]] consteval auto common_dimension(D1 d1, D2 d2)
|
|
||||||
requires(interconvertible(d1, d2))
|
|
||||||
{
|
|
||||||
if constexpr (std::derived_from<D1, D2>)
|
|
||||||
return d1;
|
|
||||||
else
|
|
||||||
return d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// TODO consider adding the support for text output of the dimensional equation
|
// TODO consider adding the support for text output of the dimensional equation
|
||||||
|
@@ -481,7 +481,7 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>
|
quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference);
|
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
||||||
using ret = quantity<ref, decltype(lhs.number() + rhs.number())>;
|
using ret = quantity<ref, decltype(lhs.number() + rhs.number())>;
|
||||||
return ret(ret(lhs).number() + ret(rhs).number());
|
return ret(ret(lhs).number() + ret(rhs).number());
|
||||||
}
|
}
|
||||||
@@ -491,7 +491,7 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>
|
quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference);
|
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
||||||
using ret = quantity<ref, decltype(lhs.number() - rhs.number())>;
|
using ret = quantity<ref, decltype(lhs.number() - rhs.number())>;
|
||||||
return ret(ret(lhs).number() - ret(rhs).number());
|
return ret(ret(lhs).number() - ret(rhs).number());
|
||||||
}
|
}
|
||||||
@@ -528,7 +528,7 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
std::three_way_comparable_with<typename Q1::rep, typename Q2::rep>
|
std::three_way_comparable_with<typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr auto operator<=>(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr auto operator<=>(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference);
|
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
||||||
return quantity_cast<ref>(lhs).number() <=> quantity_cast<ref>(rhs).number();
|
return quantity_cast<ref>(lhs).number() <=> quantity_cast<ref>(rhs).number();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +537,7 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
std::equality_comparable_with<typename Q1::rep, typename Q2::rep>
|
std::equality_comparable_with<typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr bool operator==(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr bool operator==(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference);
|
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
||||||
return quantity_cast<ref>(lhs).number() == quantity_cast<ref>(rhs).number();
|
return quantity_cast<ref>(lhs).number() == quantity_cast<ref>(rhs).number();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,13 +548,13 @@ namespace std {
|
|||||||
template<units::Quantity Q1, units::Quantity Q2>
|
template<units::Quantity Q1, units::Quantity Q2>
|
||||||
requires requires {
|
requires requires {
|
||||||
{
|
{
|
||||||
units::detail::common_reference(Q1::reference, Q2::reference)
|
units::common_reference(Q1::reference, Q2::reference)
|
||||||
} -> units::Reference;
|
} -> units::Reference;
|
||||||
typename common_type_t<typename Q1::rep, typename Q2::rep>;
|
typename common_type_t<typename Q1::rep, typename Q2::rep>;
|
||||||
}
|
}
|
||||||
struct common_type<Q1, Q2> {
|
struct common_type<Q1, Q2> {
|
||||||
public:
|
public:
|
||||||
using type = units::quantity<units::detail::common_reference(Q1::reference, Q2::reference),
|
using type = units::quantity<units::common_reference(Q1::reference, Q2::reference),
|
||||||
common_type_t<typename Q1::rep, typename Q2::rep>>;
|
common_type_t<typename Q1::rep, typename Q2::rep>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -107,20 +107,18 @@ template<Reference R1, Reference R2>
|
|||||||
return interconvertible(R1::dimension, R2::dimension) && interconvertible(R1::unit, R2::unit);
|
return interconvertible(R1::dimension, R2::dimension) && interconvertible(R1::unit, R2::unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
[[nodiscard]] consteval auto common_reference(Reference auto r1, Reference auto r2, Reference auto... rest)
|
||||||
|
|
||||||
[[nodiscard]] consteval auto common_reference(Reference auto r1, Reference auto r2)
|
|
||||||
requires requires {
|
requires requires {
|
||||||
{
|
{
|
||||||
common_dimension(r1.dimension, r2.dimension)
|
common_dimension(r1.dimension, r2.dimension, rest.dimension...)
|
||||||
} -> Dimension;
|
} -> Dimension;
|
||||||
{
|
{
|
||||||
common_unit(r1.unit, r2.unit)
|
common_unit(r1.unit, r2.unit, rest.unit...)
|
||||||
} -> Unit;
|
} -> Unit;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return reference<common_dimension(r1.dimension, r2.dimension), common_unit(r1.unit, r2.unit)>{};
|
return reference<common_dimension(r1.dimension, r2.dimension, rest.dimension...),
|
||||||
|
common_unit(r1.unit, r2.unit, rest.unit...)>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
@@ -586,16 +586,46 @@ template<Unit Lhs, Unit Rhs>
|
|||||||
canonical_lhs.mag == canonical_rhs.mag;
|
canonical_lhs.mag == canonical_rhs.mag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interconvertible
|
||||||
// Convertible
|
[[nodiscard]] consteval bool interconvertible(Unit auto u1, Unit auto u2)
|
||||||
template<Unit Lhs, Unit Rhs>
|
|
||||||
[[nodiscard]] consteval bool interconvertible(Lhs lhs, Rhs rhs)
|
|
||||||
{
|
{
|
||||||
auto canonical_lhs = detail::get_canonical_unit(lhs);
|
auto canonical_lhs = detail::get_canonical_unit(u1);
|
||||||
auto canonical_rhs = detail::get_canonical_unit(rhs);
|
auto canonical_rhs = detail::get_canonical_unit(u2);
|
||||||
return is_same_v<decltype(canonical_lhs.reference_unit), decltype(canonical_rhs.reference_unit)>;
|
return is_same_v<decltype(canonical_lhs.reference_unit), decltype(canonical_rhs.reference_unit)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common unit
|
||||||
|
[[nodiscard]] consteval auto common_unit(Unit auto u) { return u; }
|
||||||
|
|
||||||
|
template<Unit U1, Unit U2>
|
||||||
|
[[nodiscard]] consteval auto common_unit(U1 u1, U2 u2)
|
||||||
|
requires(interconvertible(u1, u2))
|
||||||
|
{
|
||||||
|
if constexpr (U1{} == U2{}) {
|
||||||
|
if constexpr (std::derived_from<U1, U2>)
|
||||||
|
return u1;
|
||||||
|
else
|
||||||
|
return u2;
|
||||||
|
} else {
|
||||||
|
constexpr auto canonical_lhs = detail::get_canonical_unit(U1{});
|
||||||
|
constexpr auto canonical_rhs = detail::get_canonical_unit(U2{});
|
||||||
|
|
||||||
|
if constexpr (is_integral(canonical_lhs.mag / canonical_rhs.mag))
|
||||||
|
return u2;
|
||||||
|
else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag))
|
||||||
|
return u1;
|
||||||
|
else {
|
||||||
|
constexpr auto cm = detail::common_magnitude(canonical_lhs.mag, canonical_rhs.mag);
|
||||||
|
return scaled_unit<cm, std::remove_const_t<decltype(canonical_lhs.reference_unit)>>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] consteval 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 common_unit(common_unit(u1, u2), u3, rest...);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Computes the value of a unit raised to the `Num/Den` power
|
* @brief Computes the value of a unit raised to the `Num/Den` power
|
||||||
@@ -814,31 +844,4 @@ template<typename CharT = char, Unit U>
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<Unit U1, Unit U2>
|
|
||||||
[[nodiscard]] consteval auto common_unit(U1 u1, U2 u2)
|
|
||||||
requires(interconvertible(u1, u2))
|
|
||||||
{
|
|
||||||
if constexpr (U1{} == U2{}) {
|
|
||||||
if constexpr (std::derived_from<U1, U2>)
|
|
||||||
return u1;
|
|
||||||
else
|
|
||||||
return u2;
|
|
||||||
} else {
|
|
||||||
constexpr auto canonical_lhs = detail::get_canonical_unit(U1{});
|
|
||||||
constexpr auto canonical_rhs = detail::get_canonical_unit(U2{});
|
|
||||||
|
|
||||||
if constexpr (is_integral(canonical_lhs.mag / canonical_rhs.mag))
|
|
||||||
return u2;
|
|
||||||
else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag))
|
|
||||||
return u1;
|
|
||||||
else {
|
|
||||||
constexpr auto cm = common_magnitude(canonical_lhs.mag, canonical_rhs.mag);
|
|
||||||
return scaled_unit<cm, std::remove_const_t<decltype(canonical_lhs.reference_unit)>>{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
Reference in New Issue
Block a user