mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-02 20:04:27 +02:00
refactor: quantity arithmetics implemented
This commit is contained in:
@@ -23,6 +23,9 @@
|
|||||||
#include <units/si/si.h>
|
#include <units/si/si.h>
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
consteval bool print();
|
||||||
|
|
||||||
template<typename T, typename Expr>
|
template<typename T, typename Expr>
|
||||||
constexpr bool is_of_type(Expr)
|
constexpr bool is_of_type(Expr)
|
||||||
{
|
{
|
||||||
@@ -34,33 +37,102 @@ namespace {
|
|||||||
using namespace units;
|
using namespace units;
|
||||||
using namespace units::si::unit_symbols;
|
using namespace units::si::unit_symbols;
|
||||||
|
|
||||||
constexpr auto power = 5 * si::power[W];
|
// clang-format off
|
||||||
static_assert(is_of_type<quantity<reference<struct isq::power_dim, struct si::watt>{}, int>>(power));
|
inline constexpr struct activity_dim : decltype(1 / isq::time_dim) {} activity_dim;
|
||||||
|
inline constexpr struct activity : system_reference<activity_dim, si::becquerel> {} activity;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
constexpr auto speed = 5 * si::speed[m / s];
|
|
||||||
|
// Named quantity/dimension and unit
|
||||||
static_assert(
|
static_assert(
|
||||||
is_of_type<quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>(
|
is_same_v<decltype(5 * si::power[W]), quantity<reference<struct isq::power_dim, struct si::watt>{}, int>>);
|
||||||
speed));
|
|
||||||
|
|
||||||
constexpr auto q = 10 * si::length[m] / (2 * si::time[s]);
|
// Named quantity/dimension and derived (unnamed) unit
|
||||||
static_assert(is_of_type<quantity<reference<derived_dimension<struct isq::length_dim, per<struct isq::time_dim>>,
|
static_assert(
|
||||||
derived_unit<struct si::metre, per<struct si::second>>>{},
|
is_same_v<decltype(5 * si::speed[m / s]),
|
||||||
int>>(q));
|
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||||
|
|
||||||
constexpr auto distance = 5 * si::speed[m / s] * (5 * si::time[s]);
|
// Derived (unnamed) quantity/dimension and derived (unnamed) unit
|
||||||
|
static_assert(is_same_v<decltype(10 * si::length[m] / (2 * si::time[s])),
|
||||||
|
quantity<reference<derived_dimension<struct isq::length_dim, per<struct isq::time_dim>>,
|
||||||
|
derived_unit<struct si::metre, per<struct si::second>>>{},
|
||||||
|
int>>);
|
||||||
|
|
||||||
static_assert(is_of_type<quantity<reference<struct isq::length_dim, struct si::metre>{}, int>>(distance));
|
// Base quantity as a result of dimensional transformation
|
||||||
|
static_assert(is_same_v<decltype(5 * si::speed[m / s] * (5 * si::time[s])),
|
||||||
|
quantity<reference<struct isq::length_dim, struct si::metre>{}, int>>);
|
||||||
|
|
||||||
constexpr auto dimensionless = 20 * si::speed[m / s] / (10 * si::length[m]) * (5 * si::time[s]);
|
// Dimensionless
|
||||||
|
static_assert(is_same_v<decltype(20 * si::speed[m / s] / (10 * si::length[m]) * (5 * si::time[s])),
|
||||||
|
quantity<reference<struct one_dim, struct one>{}, int>>);
|
||||||
|
|
||||||
static_assert(is_of_type<quantity<reference<struct one_dim, struct one>{}, int>>(dimensionless));
|
// Comparisons
|
||||||
|
|
||||||
|
// Named and derived dimensions (same units)
|
||||||
|
static_assert(10 * si::length[m] / (2 * si::time[s]) == 5 * si::speed[m / s]);
|
||||||
|
static_assert(5 * si::speed[m / s] == 10 * si::length[m] / (2 * si::time[s]));
|
||||||
|
|
||||||
// constexpr auto q1 = 10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s];
|
// Named and derived dimensions (different units)
|
||||||
// static_assert(is_of_type<quantity<reference<derived_dimension<struct isq::length_dim, per<struct isq::time_dim>>,
|
static_assert(10 / (2 * si::time[s]) == 5 * si::frequency[Hz]);
|
||||||
// derived_unit<struct si::metre, per<struct si::second>>>{},
|
static_assert(5 * si::frequency[Hz] == 10 / (2 * si::time[s]));
|
||||||
// int>>(q1));
|
|
||||||
|
|
||||||
|
// Different named dimensions
|
||||||
|
template<Reference auto R1, Reference auto R2>
|
||||||
|
concept invalid_comparison = requires {
|
||||||
|
requires !requires { 2 * R1 == 2 * R2; };
|
||||||
|
requires !requires { 2 * R2 == 2 * R1; };
|
||||||
|
};
|
||||||
|
static_assert(invalid_comparison<activity[Bq], si::frequency[Hz]>);
|
||||||
|
|
||||||
|
// static_assert(print<decltype(10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s])>());
|
||||||
|
|
||||||
|
// Arithmetics
|
||||||
|
|
||||||
|
// Named and derived dimensions (same units)
|
||||||
|
static_assert(10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s] == 10 * si::speed[m / s]);
|
||||||
|
static_assert(5 * si::speed[m / s] + 10 * si::length[m] / (2 * si::time[s]) == 10 * si::speed[m / s]);
|
||||||
|
static_assert(10 * si::length[m] / (2 * si::time[s]) - 5 * si::speed[m / s] == 0 * si::speed[m / s]);
|
||||||
|
static_assert(5 * si::speed[m / s] - 10 * si::length[m] / (2 * si::time[s]) == 0 * si::speed[m / s]);
|
||||||
|
static_assert(
|
||||||
|
is_same_v<decltype(10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s]),
|
||||||
|
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||||
|
static_assert(
|
||||||
|
is_same_v<decltype(5 * si::speed[m / s] + 10 * si::length[m] / (2 * si::time[s])),
|
||||||
|
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||||
|
static_assert(
|
||||||
|
is_same_v<decltype(10 * si::length[m] / (2 * si::time[s]) - 5 * si::speed[m / s]),
|
||||||
|
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||||
|
static_assert(
|
||||||
|
is_same_v<decltype(5 * si::speed[m / s] - 10 * si::length[m] / (2 * si::time[s])),
|
||||||
|
quantity<reference<struct isq::speed_dim, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
||||||
|
|
||||||
|
// Named and derived dimensions (different units)
|
||||||
|
static_assert(10 / (2 * si::time[s]) + 5 * si::frequency[Hz] == 10 * si::frequency[Hz]);
|
||||||
|
static_assert(5 * si::frequency[Hz] + 10 / (2 * si::time[s]) == 10 * si::frequency[Hz]);
|
||||||
|
static_assert(10 / (2 * si::time[s]) - 5 * si::frequency[Hz] == 0 * si::frequency[Hz]);
|
||||||
|
static_assert(5 * si::frequency[Hz] - 10 / (2 * si::time[s]) == 0 * si::frequency[Hz]);
|
||||||
|
static_assert(is_same_v<decltype(10 / (2 * si::time[s]) + 5 * si::frequency[Hz]),
|
||||||
|
quantity<reference<struct isq::frequency_dim, struct si::hertz>{}, int>>);
|
||||||
|
static_assert(is_same_v<decltype(5 * si::frequency[Hz] + 10 / (2 * si::time[s])),
|
||||||
|
quantity<reference<struct isq::frequency_dim, struct si::hertz>{}, int>>);
|
||||||
|
static_assert(is_same_v<decltype(10 / (2 * si::time[s]) - 5 * si::frequency[Hz]),
|
||||||
|
quantity<reference<struct isq::frequency_dim, struct si::hertz>{}, int>>);
|
||||||
|
static_assert(is_same_v<decltype(5 * si::frequency[Hz] - 10 / (2 * si::time[s])),
|
||||||
|
quantity<reference<struct isq::frequency_dim, struct si::hertz>{}, int>>);
|
||||||
|
|
||||||
|
// Different named dimensions
|
||||||
|
template<typename... Ts>
|
||||||
|
consteval bool invalid_arithmetic(Ts... ts)
|
||||||
|
{
|
||||||
|
return requires {
|
||||||
|
requires !requires { (... + ts); };
|
||||||
|
requires !requires { (... - ts); };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static_assert(invalid_arithmetic(5 * activity[Bq], 5 * si::frequency[Hz]));
|
||||||
|
static_assert(invalid_arithmetic(5 * activity[Bq], 10 / (2 * si::time[s]), 5 * si::frequency[Hz]));
|
||||||
|
|
||||||
|
// static_assert(quantity_of<decltype(60 * si::speed[km / h]), isq::speed_dim>);
|
||||||
// static_assert(quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), isq::speed_dim>);
|
// static_assert(quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), isq::speed_dim>);
|
||||||
// static_assert(quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), si::speed[km / h]>);
|
// static_assert(quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), si::speed[km / h]>);
|
||||||
// static_assert(!quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), si::speed[m / s]>);
|
// static_assert(!quantity_of<decltype(120 * si::length[km] / (2 * si::time[h])), si::speed[m / s]>);
|
||||||
@@ -222,8 +294,6 @@ namespace units::isq::si {
|
|||||||
// quantity<speed[km / s]> speed3(20);
|
// quantity<speed[km / s]> speed3(20);
|
||||||
// quantity<length[m] / si::time[s]> speed4(20);
|
// quantity<length[m] / si::time[s]> speed4(20);
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void print();
|
|
||||||
|
|
||||||
// constexpr auto avg_speed(quantity<length[km]> d, quantity<si::time[h]> t) { return d / t; }
|
// constexpr auto avg_speed(quantity<length[km]> d, quantity<si::time[h]> t) { return d / t; }
|
||||||
|
|
||||||
|
@@ -1,122 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/concepts.h>
|
|
||||||
#include <units/dimension.h>
|
|
||||||
#include <units/unit.h>
|
|
||||||
// #include <units/bits/equivalent.h>
|
|
||||||
// #include <units/quantity_cast.h>
|
|
||||||
|
|
||||||
namespace units {
|
|
||||||
|
|
||||||
// template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep>
|
|
||||||
// class quantity_point;
|
|
||||||
|
|
||||||
// template<Kind K, UnitOf<typename K::dimension> U, Representation Rep>
|
|
||||||
// class quantity_kind;
|
|
||||||
|
|
||||||
// template<PointKind PK, UnitOf<typename PK::dimension> U, Representation Rep>
|
|
||||||
// class quantity_point_kind;
|
|
||||||
|
|
||||||
// TODO common_unit should use common_magnitude(U1::mag, U2::mag)
|
|
||||||
|
|
||||||
template<Dimension D1, Dimension D2>
|
|
||||||
requires(equivalent(D1{}, D2{}))
|
|
||||||
using common_dimension = conditional<std::is_same_v<D1, D2>, D1, detail::dim_type<D1>>;
|
|
||||||
|
|
||||||
template<Unit U1, Unit U2>
|
|
||||||
// requires(equivalent<U1, U2>)
|
|
||||||
using common_unit = U1;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename R1, typename R2>
|
|
||||||
struct common_quantity_reference_impl;
|
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
struct common_quantity_reference_impl<R, R> {
|
|
||||||
using type = R;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename D, typename U1, typename U2>
|
|
||||||
struct common_quantity_reference_impl<reference<D, U1>, reference<D, U2>> {
|
|
||||||
using type = reference<D, common_unit<U1, U2>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename R1, typename R2>
|
|
||||||
requires(equivalent(R1::dimension, R2::dimension))
|
|
||||||
struct common_quantity_reference_impl<R1, R2> {
|
|
||||||
using type = reference<common_dimension<decltype(R1::dimension), decltype(R2::dimension)>,
|
|
||||||
common_unit<decltype(R1::unit), decltype(R2::unit)>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<Quantity Q1, quantity_equivalent_to<Q1> Q2>
|
|
||||||
using common_quantity_reference =
|
|
||||||
TYPENAME detail::common_quantity_reference_impl<std::remove_const_t<decltype(Q1::reference)>,
|
|
||||||
std::remove_const_t<decltype(Q2::reference)>>::type;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace units
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
template<units::Quantity Q1, units::quantity_equivalent_to<Q1> Q2>
|
|
||||||
requires requires { typename common_type_t<typename Q1::rep, typename Q2::rep>; }
|
|
||||||
struct common_type<Q1, Q2> {
|
|
||||||
private:
|
|
||||||
using ref = units::detail::common_quantity_reference<Q1, Q2>;
|
|
||||||
public:
|
|
||||||
using type = units::quantity<ref{}, common_type_t<typename Q1::rep, typename Q2::rep>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// template<units::QuantityPoint QP1, units::QuantityPointEquivalentTo<QP1> QP2>
|
|
||||||
// requires requires { typename common_type_t<typename QP1::rep, typename QP2::rep>; }
|
|
||||||
// struct common_type<QP1, QP2> {
|
|
||||||
// using type =
|
|
||||||
// units::quantity_point<units::rebind_point_origin_dimension<
|
|
||||||
// typename QP1::origin, typename common_type_t<typename QP1::quantity_type,
|
|
||||||
// typename QP2::quantity_type>::dimension>,
|
|
||||||
// typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::unit,
|
|
||||||
// typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::rep>;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// template<units::QuantityKind QK1, units::QuantityKindEquivalentTo<QK1> QK2>
|
|
||||||
// requires requires { typename common_type_t<typename QK1::rep, typename QK2::rep>; }
|
|
||||||
// struct common_type<QK1, QK2> {
|
|
||||||
// using type =
|
|
||||||
// units::quantity_kind<typename QK1::kind_type,
|
|
||||||
// typename common_type_t<typename QK1::quantity_type, typename QK2::quantity_type>::unit,
|
|
||||||
// typename common_type_t<typename QK1::quantity_type, typename QK2::quantity_type>::rep>;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// template<units::QuantityPointKind QPK1, units::QuantityPointKindEquivalentTo<QPK1> QPK2>
|
|
||||||
// requires requires { typename common_type_t<typename QPK1::rep, typename QPK2::rep>; }
|
|
||||||
// struct common_type<QPK1, QPK2> {
|
|
||||||
// using type = units::quantity_point_kind<
|
|
||||||
// typename QPK1::point_kind_type,
|
|
||||||
// typename common_type_t<typename QPK1::quantity_kind_type, typename QPK2::quantity_kind_type>::unit,
|
|
||||||
// typename common_type_t<typename QPK1::quantity_kind_type, typename QPK2::quantity_kind_type>::rep>;
|
|
||||||
// };
|
|
||||||
|
|
||||||
} // namespace std
|
|
@@ -102,15 +102,7 @@ inline constexpr bool is_quantity<quantity<R, Rep>> = true;
|
|||||||
*/
|
*/
|
||||||
template<typename Q, auto V>
|
template<typename Q, auto V>
|
||||||
concept quantity_of = Quantity<Q> && ((Dimension<std::remove_const_t<decltype(V)>> && Q::dimension == V) ||
|
concept quantity_of = Quantity<Q> && ((Dimension<std::remove_const_t<decltype(V)>> && Q::dimension == V) ||
|
||||||
(Reference<std::remove_const_t<decltype(V)>> && Q::dimension == V.dimension));
|
(Reference<std::remove_const_t<decltype(V)>> && Q::dimension == V.dimension &&
|
||||||
|
Q::unit == V.unit));
|
||||||
/**
|
|
||||||
* @brief A concept matching two equivalent quantities
|
|
||||||
*
|
|
||||||
* Satisfied by quantities having equivalent dimensions and units.
|
|
||||||
*/
|
|
||||||
template<typename Q1, typename Q2>
|
|
||||||
concept quantity_equivalent_to = Quantity<Q1> && equivalent(Q1::dimension, Q2::dimension) &&
|
|
||||||
equivalent(Q1::unit, Q2::unit);
|
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
@@ -195,6 +195,23 @@ template<Dimension D1, Dimension D2>
|
|||||||
return is_same_v<detail::dim_type<D1>, detail::dim_type<D2>>;
|
return is_same_v<detail::dim_type<D1>, detail::dim_type<D2>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<Dimension D1, Dimension D2>
|
||||||
|
[[nodiscard]] consteval bool convertible(D1, D2)
|
||||||
|
{
|
||||||
|
return std::derived_from<D1, D2> || std::derived_from<D2, D1>;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO consider adding the support for text output of the dimensional equation
|
// TODO consider adding the support for text output of the dimensional equation
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template<units::Dimension D1, units::Dimension D2>
|
||||||
|
requires(units::convertible(D1{}, D2{}))
|
||||||
|
struct common_type<D1, D2> {
|
||||||
|
using type = ::units::conditional<std::derived_from<std::remove_const_t<D1>, std::remove_const_t<D2>>,
|
||||||
|
std::remove_const_t<D1>, std::remove_const_t<D2>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
@@ -23,13 +23,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// #include <units/bits/common_type.h>
|
|
||||||
// #include <units/generic/dimensionless.h>
|
|
||||||
|
|
||||||
// IWYU pragma: begin_exports
|
// IWYU pragma: begin_exports
|
||||||
// #include <units/quantity_cast.h>
|
#include <units/quantity_cast.h>
|
||||||
// #include <units/ratio.h>
|
// #include <units/ratio.h>
|
||||||
#include <units/bits/common_type.h>
|
|
||||||
#include <units/concepts.h>
|
#include <units/concepts.h>
|
||||||
#include <units/customization_points.h>
|
#include <units/customization_points.h>
|
||||||
#include <units/dimension.h>
|
#include <units/dimension.h>
|
||||||
@@ -38,8 +34,7 @@
|
|||||||
#include <compare>
|
#include <compare>
|
||||||
// IWYU pragma: end_exports
|
// IWYU pragma: end_exports
|
||||||
|
|
||||||
// #include <units/reference.h>
|
#include <utility>
|
||||||
// #include <utility>
|
|
||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
@@ -73,8 +68,9 @@ concept harmonic_ = // exposition only
|
|||||||
// Quantity<QFrom> && Quantity<QTo> && is_integral(detail::quantity_magnitude<QFrom> / detail::quantity_magnitude<QTo>);
|
// Quantity<QFrom> && Quantity<QTo> && is_integral(detail::quantity_magnitude<QFrom> / detail::quantity_magnitude<QTo>);
|
||||||
|
|
||||||
template<typename QFrom, typename QTo>
|
template<typename QFrom, typename QTo>
|
||||||
concept safe_castable_to_ = // exposition only
|
concept quantity_convertible_to_ = // exposition only
|
||||||
Quantity<QFrom> && quantity_of<QTo, QFrom::dimension> && scalable_with_<typename QFrom::rep, typename QTo::rep> &&
|
Quantity<QFrom> && Quantity<QTo> && convertible(QFrom::dimension, QTo::dimension) &&
|
||||||
|
convertible(QFrom::unit, QTo::unit) && scalable_with_<typename QFrom::rep, typename QTo::rep> &&
|
||||||
(floating_point_<QTo> || (!floating_point_<QFrom> && harmonic_<QFrom, QTo>));
|
(floating_point_<QTo> || (!floating_point_<QFrom> && harmonic_<QFrom, QTo>));
|
||||||
|
|
||||||
template<typename Func, typename T, typename U>
|
template<typename Func, typename T, typename U>
|
||||||
@@ -161,13 +157,13 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<safe_castable_to_<quantity> Q>
|
template<quantity_convertible_to_<quantity> Q>
|
||||||
constexpr explicit(false) quantity(const Q& q) : number_(quantity_cast<quantity>(q).number())
|
constexpr explicit(false) quantity(const Q& q) : number_(quantity_cast<quantity>(q).number())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<QuantityLike Q>
|
template<QuantityLike Q>
|
||||||
requires(safe_castable_to_<quantity_like_type<Q>, quantity>)
|
requires(quantity_convertible_to_<quantity_like_type<Q>, quantity>)
|
||||||
constexpr explicit quantity(const Q& q) : quantity(quantity_like_type<Q>(quantity_like_traits<Q>::number(q)))
|
constexpr explicit quantity(const Q& q) : quantity(quantity_like_type<Q>(quantity_like_traits<Q>::number(q)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -423,7 +419,7 @@ public:
|
|||||||
requires(!Quantity<Value>) && (invoke_result_convertible_to_<rep, std::divides<>, const Value&, rep>)
|
requires(!Quantity<Value>) && (invoke_result_convertible_to_<rep, std::divides<>, const Value&, rep>)
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
|
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
|
||||||
{
|
{
|
||||||
return detail::make_quantity<dimensionless[one] / reference>(v / q.number());
|
return detail::make_quantity<dimensionless[::units::one] / reference>(v / q.number());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
@@ -475,20 +471,20 @@ explicit quantity(Q)
|
|||||||
typename quantity_like_traits<Q>::rep>;
|
typename quantity_like_traits<Q>::rep>;
|
||||||
|
|
||||||
// non-member binary operators
|
// non-member binary operators
|
||||||
template<Quantity Q1, quantity_equivalent_to<Q1> Q2>
|
template<Quantity Q1, std::convertible_to<Q1> Q2>
|
||||||
requires(quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>)
|
requires(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)
|
||||||
{
|
{
|
||||||
using ref = detail::common_quantity_reference<Q1, Q2>;
|
using ref = std::common_type_t<decltype(Q1::reference), decltype(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());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q1, quantity_equivalent_to<Q1> Q2>
|
template<Quantity Q1, std::convertible_to<Q1> Q2>
|
||||||
requires(quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>)
|
requires(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)
|
||||||
{
|
{
|
||||||
using ref = detail::common_quantity_reference<Q1, Q2>;
|
using ref = std::common_type_t<decltype(Q1::reference), decltype(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());
|
||||||
}
|
}
|
||||||
@@ -510,7 +506,7 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
|
|
||||||
template<Quantity Q1, Quantity Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires(!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
|
requires(!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
|
||||||
(quantity_equivalent_to<Q2, Q1> || quantity_of<Q2, one_dim>) &&
|
(std::convertible_to<Q2, Q1> || quantity_of<Q2, one_dim>) &&
|
||||||
(quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>)
|
(quantity_value_for_<std::modulus<>, 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)
|
||||||
{
|
{
|
||||||
@@ -520,20 +516,36 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
return ret(lhs.number() % rhs.number());
|
return ret(lhs.number() % rhs.number());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q1, quantity_equivalent_to<Q1> Q2>
|
template<Quantity Q1, std::convertible_to<Q1> Q2>
|
||||||
requires std::three_way_comparable_with<typename Q1::rep, typename Q2::rep>
|
requires 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)
|
||||||
{
|
{
|
||||||
using cq = std::common_type_t<Q1, Q2>;
|
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
||||||
return cq(lhs).number() <=> cq(rhs).number();
|
return quantity_cast<ref>(lhs).number() <=> quantity_cast<ref>(rhs).number();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q1, quantity_equivalent_to<Q1> Q2>
|
template<Quantity Q1, std::convertible_to<Q1> Q2>
|
||||||
requires std::equality_comparable_with<typename Q1::rep, typename Q2::rep>
|
requires 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)
|
||||||
{
|
{
|
||||||
using cq = std::common_type_t<Q1, Q2>;
|
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
||||||
return cq(lhs).number() == cq(rhs).number();
|
return quantity_cast<ref{}>(lhs).number() == quantity_cast<ref{}>(rhs).number();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template<units::Quantity Q1, units::Quantity Q2>
|
||||||
|
requires requires {
|
||||||
|
typename common_type_t<remove_const_t<decltype(Q1::reference)>, remove_const_t<decltype(Q2::reference)>>;
|
||||||
|
typename common_type_t<typename Q1::rep, typename Q2::rep>;
|
||||||
|
}
|
||||||
|
struct common_type<Q1, Q2> {
|
||||||
|
private:
|
||||||
|
using ref = common_type_t<remove_const_t<decltype(Q1::reference)>, remove_const_t<decltype(Q2::reference)>>;
|
||||||
|
public:
|
||||||
|
using type = units::quantity<ref{}, common_type_t<typename Q1::rep, typename Q2::rep>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
@@ -22,12 +22,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <units/bits/dimension_op.h>
|
|
||||||
#include <units/bits/external/type_traits.h>
|
#include <units/bits/external/type_traits.h>
|
||||||
#include <units/concepts.h>
|
#include <units/concepts.h>
|
||||||
#include <units/customization_points.h>
|
#include <units/customization_points.h>
|
||||||
|
#include <units/dimension.h>
|
||||||
#include <units/magnitude.h>
|
#include <units/magnitude.h>
|
||||||
#include <units/reference.h>
|
#include <units/reference.h>
|
||||||
|
#include <units/unit.h>
|
||||||
|
|
||||||
UNITS_DIAGNOSTIC_PUSH
|
UNITS_DIAGNOSTIC_PUSH
|
||||||
// warning C4244: 'argument': conversion from 'intmax_t' to 'T', possible loss of data with T=int
|
// warning C4244: 'argument': conversion from 'intmax_t' to 'T', possible loss of data with T=int
|
||||||
@@ -35,53 +36,53 @@ UNITS_DIAGNOSTIC_IGNORE_LOSS_OF_DATA
|
|||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
template<Dimension D, UnitOf<D> U, Representation Rep>
|
template<Reference auto R, Representation Rep>
|
||||||
class quantity;
|
class quantity;
|
||||||
|
|
||||||
template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep>
|
// template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep>
|
||||||
class quantity_point;
|
// class quantity_point;
|
||||||
|
|
||||||
template<Kind K, UnitOf<typename K::dimension> U, Representation Rep>
|
// template<Kind K, UnitOf<typename K::dimension> U, Representation Rep>
|
||||||
class quantity_kind;
|
// class quantity_kind;
|
||||||
|
|
||||||
template<PointKind PK, UnitOf<typename PK::dimension> U, Representation Rep>
|
// template<PointKind PK, UnitOf<typename PK::dimension> U, Representation Rep>
|
||||||
class quantity_point_kind;
|
// class quantity_point_kind;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<Quantity Q>
|
// template<Quantity Q>
|
||||||
inline constexpr Magnitude auto quantity_magnitude = decltype(Q::reference)::mag;
|
// inline constexpr Magnitude auto quantity_magnitude = decltype(Q::reference)::mag;
|
||||||
|
|
||||||
template<typename QFrom, typename QTo>
|
// template<typename QFrom, typename QTo>
|
||||||
inline constexpr Magnitude auto cast_magnitude = [] {
|
// inline constexpr Magnitude auto cast_magnitude = [] {
|
||||||
using FromU = TYPENAME QFrom::unit;
|
// using FromU = TYPENAME QFrom::unit;
|
||||||
using ToU = TYPENAME QTo::unit;
|
// using ToU = TYPENAME QTo::unit;
|
||||||
if constexpr (same_unit_reference<FromU, ToU>::value) {
|
// if constexpr (same_unit_reference<FromU, ToU>::value) {
|
||||||
return FromU::mag / ToU::mag;
|
// return FromU::mag / ToU::mag;
|
||||||
} else {
|
// } else {
|
||||||
return quantity_magnitude<QFrom> / quantity_magnitude<QTo>;
|
// return quantity_magnitude<QFrom> / quantity_magnitude<QTo>;
|
||||||
}
|
// }
|
||||||
}();
|
// }();
|
||||||
|
|
||||||
template<typename From, typename To>
|
// template<typename From, typename To>
|
||||||
struct cast_traits;
|
// struct cast_traits;
|
||||||
|
|
||||||
template<typename From, typename To>
|
// template<typename From, typename To>
|
||||||
requires common_type_with_<std::common_type_t<From, To>, std::intmax_t>
|
// requires common_type_with_<std::common_type_t<From, To>, std::intmax_t>
|
||||||
struct cast_traits<From, To> {
|
// struct cast_traits<From, To> {
|
||||||
using ratio_type = std::common_type_t<std::common_type_t<From, To>, std::intmax_t>;
|
// using ratio_type = std::common_type_t<std::common_type_t<From, To>, std::intmax_t>;
|
||||||
using rep_type = ratio_type;
|
// using rep_type = ratio_type;
|
||||||
};
|
// };
|
||||||
|
|
||||||
template<typename From, typename To>
|
// template<typename From, typename To>
|
||||||
requires(!common_type_with_<std::common_type_t<From, To>, std::intmax_t> &&
|
// requires(!common_type_with_<std::common_type_t<From, To>, std::intmax_t> &&
|
||||||
scalable_number_<std::common_type_t<From, To>, std::intmax_t> &&
|
// scalable_number_<std::common_type_t<From, To>, std::intmax_t> &&
|
||||||
requires { typename std::common_type_t<From, To>::value_type; } &&
|
// requires { typename std::common_type_t<From, To>::value_type; } &&
|
||||||
common_type_with_<typename std::common_type_t<From, To>::value_type, std::intmax_t>)
|
// common_type_with_<typename std::common_type_t<From, To>::value_type, std::intmax_t>)
|
||||||
struct cast_traits<From, To> {
|
// struct cast_traits<From, To> {
|
||||||
using ratio_type = std::common_type_t<typename std::common_type_t<From, To>::value_type, std::intmax_t>;
|
// using ratio_type = std::common_type_t<typename std::common_type_t<From, To>::value_type, std::intmax_t>;
|
||||||
using rep_type = std::common_type_t<From, To>;
|
// using rep_type = std::common_type_t<From, To>;
|
||||||
};
|
// };
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
@@ -97,59 +98,28 @@ struct cast_traits<From, To> {
|
|||||||
*
|
*
|
||||||
* @tparam To a target quantity type to cast to
|
* @tparam To a target quantity type to cast to
|
||||||
*/
|
*/
|
||||||
template<Quantity To, typename D, typename U, scalable_with_<typename To::rep> Rep>
|
template<Quantity To, auto R, scalable_with_<typename To::rep> Rep>
|
||||||
requires QuantityOf<To, D> && (std::constructible_from<typename To::rep, std::common_type_t<typename To::rep, Rep>>)
|
requires(convertible(R, To::reference))
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
using traits = detail::cast_traits<Rep, typename To::rep>;
|
// TODO implement same unit magnitude check
|
||||||
using ratio_type = TYPENAME traits::ratio_type;
|
if constexpr (std::same_as<decltype(R.unit), decltype(To::unit)>) {
|
||||||
using rep_type = TYPENAME traits::rep_type;
|
return To(static_cast<TYPENAME To::rep>(q.number()));
|
||||||
|
} else {
|
||||||
|
// using traits = detail::cast_traits<Rep, typename To::rep>;
|
||||||
|
// using ratio_type = TYPENAME traits::ratio_type;
|
||||||
|
// using rep_type = TYPENAME traits::rep_type;
|
||||||
|
|
||||||
constexpr Magnitude auto c_mag = detail::cast_magnitude<quantity<D, U, Rep>, To>;
|
// constexpr Magnitude auto c_mag = detail::cast_magnitude<quantity<D, U, Rep>, To>;
|
||||||
constexpr Magnitude auto num = numerator(c_mag);
|
// constexpr Magnitude auto num = numerator(c_mag);
|
||||||
constexpr Magnitude auto den = denominator(c_mag);
|
// constexpr Magnitude auto den = denominator(c_mag);
|
||||||
constexpr Magnitude auto irr = c_mag * (den / num);
|
// constexpr Magnitude auto irr = c_mag * (den / num);
|
||||||
|
|
||||||
constexpr auto val = [](Magnitude auto m) { return get_value<ratio_type>(m); };
|
// constexpr auto val = [](Magnitude auto m) { return get_value<ratio_type>(m); };
|
||||||
return To(static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) * val(num) / val(den) * val(irr)));
|
// return To(static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) * val(num) / val(den) * val(irr)));
|
||||||
}
|
// TODO implement that
|
||||||
|
return q;
|
||||||
/**
|
}
|
||||||
* @brief Explicit cast of a quantity
|
|
||||||
*
|
|
||||||
* Implicit conversions between quantities of different types are allowed only for "safe"
|
|
||||||
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
|
|
||||||
*
|
|
||||||
* This cast gets only the target dimension to cast to. For example:
|
|
||||||
*
|
|
||||||
* auto q1 = units::quantity_cast<units::isq::si::dim_acceleration>(200_q_Gal);
|
|
||||||
*
|
|
||||||
* @tparam ToD a dimension type to use for a target quantity
|
|
||||||
*/
|
|
||||||
template<Dimension ToD, typename D, typename U, typename Rep>
|
|
||||||
requires equivalent<ToD, D>
|
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
|
||||||
{
|
|
||||||
return quantity_cast<quantity<ToD, downcast_unit<ToD, U::mag>, Rep>>(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Explicit cast of a quantity
|
|
||||||
*
|
|
||||||
* Implicit conversions between quantities of different types are allowed only for "safe"
|
|
||||||
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
|
|
||||||
*
|
|
||||||
* This cast gets only the target unit to cast to. For example:
|
|
||||||
*
|
|
||||||
* auto q1 = units::quantity_cast<units::isq::si::second>(1_q_ms);
|
|
||||||
*
|
|
||||||
* @tparam ToU a unit type to use for a target quantity
|
|
||||||
*/
|
|
||||||
template<Unit ToU, typename D, typename U, typename Rep>
|
|
||||||
requires UnitOf<ToU, D>
|
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
|
||||||
{
|
|
||||||
return quantity_cast<quantity<D, ToU, Rep>>(q);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,11 +138,52 @@ template<Unit ToU, typename D, typename U, typename Rep>
|
|||||||
* @tparam ToD a dimension type to use for a target quantity
|
* @tparam ToD a dimension type to use for a target quantity
|
||||||
* @tparam ToU a unit type to use for a target quantity
|
* @tparam ToU a unit type to use for a target quantity
|
||||||
*/
|
*/
|
||||||
template<Dimension ToD, Unit ToU, typename D, typename U, typename Rep>
|
template<Reference auto ToR, auto R, typename Rep>
|
||||||
requires equivalent<ToD, D> && UnitOf<ToU, ToD>
|
requires(convertible(ToR, R))
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
return quantity_cast<quantity<ToD, ToU, Rep>>(q);
|
return quantity_cast<quantity<ToR, Rep>>(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Explicit cast of a quantity
|
||||||
|
*
|
||||||
|
* Implicit conversions between quantities of different types are allowed only for "safe"
|
||||||
|
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
|
||||||
|
*
|
||||||
|
* This cast gets only the target dimension to cast to. For example:
|
||||||
|
*
|
||||||
|
* auto q1 = units::quantity_cast<units::isq::si::dim_acceleration>(200_q_Gal);
|
||||||
|
*
|
||||||
|
* @tparam ToD a dimension type to use for a target quantity
|
||||||
|
*/
|
||||||
|
template<Dimension auto ToD, auto R, typename Rep>
|
||||||
|
requires(convertible(ToD, R.dimension))
|
||||||
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
|
{
|
||||||
|
constexpr reference<std::remove_const_t<decltype(ToD)>, std::remove_const_t<decltype(R.unit)>> r;
|
||||||
|
return quantity_cast<quantity<r, Rep>>(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Explicit cast of a quantity
|
||||||
|
*
|
||||||
|
* Implicit conversions between quantities of different types are allowed only for "safe"
|
||||||
|
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
|
||||||
|
*
|
||||||
|
* This cast gets only the target unit to cast to. For example:
|
||||||
|
*
|
||||||
|
* auto q1 = units::quantity_cast<units::isq::si::second>(1_q_ms);
|
||||||
|
*
|
||||||
|
* @tparam ToU a unit type to use for a target quantity
|
||||||
|
*/
|
||||||
|
template<Unit auto ToU, auto R, typename Rep>
|
||||||
|
requires(convertible(ToU, R.unit))
|
||||||
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
|
{
|
||||||
|
constexpr reference<std::remove_const_t<decltype(R.dimension)>, std::remove_const_t<decltype(ToU)>> r;
|
||||||
|
return quantity_cast<quantity<r, Rep>>(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -187,185 +198,187 @@ template<Dimension ToD, Unit ToU, typename D, typename U, typename Rep>
|
|||||||
*
|
*
|
||||||
* @tparam ToRep a representation type to use for a target quantity
|
* @tparam ToRep a representation type to use for a target quantity
|
||||||
*/
|
*/
|
||||||
template<Representation ToRep, typename D, typename U, scalable_with_<ToRep> Rep>
|
template<Representation ToRep, auto R, scalable_with_<ToRep> Rep>
|
||||||
requires(std::constructible_from<ToRep, std::common_type_t<ToRep, Rep>>)
|
// requires(std::constructible_from<ToRep, std::common_type_t<ToRep, Rep>>)
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
return quantity_cast<quantity<D, U, ToRep>>(q);
|
return To(static_cast<ToRep>(q.number()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @brief Explicit cast of a quantity point
|
// * @brief Explicit cast of a quantity point
|
||||||
*
|
// *
|
||||||
* Implicit conversions between quantity points of different types are allowed only for "safe"
|
// * Implicit conversions between quantity points of different types are allowed only for "safe"
|
||||||
* (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||||
*
|
// *
|
||||||
* This cast gets the target quantity point type to cast to or anything that works for quantity_cast. For example:
|
// * This cast gets the target quantity point type to cast to or anything that works for quantity_cast. For example:
|
||||||
*
|
// *
|
||||||
* auto q1 = units::quantity_point_cast<decltype(quantity_point{0_q_s})>(quantity_point{1_q_ms});
|
// * auto q1 = units::quantity_point_cast<decltype(quantity_point{0_q_s})>(quantity_point{1_q_ms});
|
||||||
* auto q1 = units::quantity_point_cast<units::isq::si::time<units::isq::si::second>>(quantity_point{1_q_ms});
|
// * auto q1 = units::quantity_point_cast<units::isq::si::time<units::isq::si::second>>(quantity_point{1_q_ms});
|
||||||
* auto q1 = units::quantity_point_cast<units::isq::si::dim_acceleration>(quantity_point{200_q_Gal});
|
// * auto q1 = units::quantity_point_cast<units::isq::si::dim_acceleration>(quantity_point{200_q_Gal});
|
||||||
* auto q1 = units::quantity_point_cast<units::isq::si::second>(quantity_point{1_q_ms});
|
// * auto q1 = units::quantity_point_cast<units::isq::si::second>(quantity_point{1_q_ms});
|
||||||
* auto q1 = units::quantity_point_cast<int>(quantity_point{1_q_ms});
|
// * auto q1 = units::quantity_point_cast<int>(quantity_point{1_q_ms});
|
||||||
*
|
// *
|
||||||
* @tparam CastSpec a target quantity point type to cast to or anything that works for quantity_cast
|
// * @tparam CastSpec a target quantity point type to cast to or anything that works for quantity_cast
|
||||||
*/
|
// */
|
||||||
template<typename CastSpec, typename O, typename U, typename Rep>
|
// template<typename CastSpec, typename O, typename U, typename Rep>
|
||||||
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<O, U, Rep>& qp)
|
// [[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<O, U, Rep>& qp)
|
||||||
requires requires {
|
// requires requires {
|
||||||
requires is_specialization_of<CastSpec, quantity_point>;
|
// requires is_specialization_of<CastSpec, quantity_point>;
|
||||||
requires requires { quantity_cast<typename CastSpec::quantity_type>(qp.relative()); };
|
// requires requires { quantity_cast<typename CastSpec::quantity_type>(qp.relative()); };
|
||||||
requires equivalent<O, typename CastSpec::origin>;
|
// requires equivalent<O, typename CastSpec::origin>;
|
||||||
} || // TODO: Simplify when Clang catches up.
|
// } || // TODO: Simplify when Clang catches up.
|
||||||
requires { quantity_cast<CastSpec>(qp.relative()); }
|
// requires { quantity_cast<CastSpec>(qp.relative()); }
|
||||||
{
|
// {
|
||||||
if constexpr (is_specialization_of<CastSpec, quantity_point>)
|
// if constexpr (is_specialization_of<CastSpec, quantity_point>)
|
||||||
return quantity_point(quantity_cast<typename CastSpec::quantity_type>(qp.relative()));
|
// return quantity_point(quantity_cast<typename CastSpec::quantity_type>(qp.relative()));
|
||||||
else
|
// else
|
||||||
return quantity_point(quantity_cast<CastSpec>(qp.relative()));
|
// return quantity_point(quantity_cast<CastSpec>(qp.relative()));
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @brief Explicit cast of a quantity point
|
// * @brief Explicit cast of a quantity point
|
||||||
*
|
// *
|
||||||
* Implicit conversions between quantity points of different types are allowed only for "safe"
|
// * Implicit conversions between quantity points of different types are allowed only for "safe"
|
||||||
* (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||||
*
|
// *
|
||||||
* This cast gets both the target dimension and unit to cast to. For example:
|
// * This cast gets both the target dimension and unit to cast to. For example:
|
||||||
*
|
// *
|
||||||
* auto q1 = units::quantity_point_cast<units::isq::si::dim_speed, units::isq::si::kilometre_per_hour>(v1);
|
// * auto q1 = units::quantity_point_cast<units::isq::si::dim_speed, units::isq::si::kilometre_per_hour>(v1);
|
||||||
*
|
// *
|
||||||
* @note This cast is especially useful when working with quantity points of unknown dimensions
|
// * @note This cast is especially useful when working with quantity points of unknown dimensions
|
||||||
* (@c unknown_dimension).
|
// * (@c unknown_dimension).
|
||||||
*
|
// *
|
||||||
* @tparam ToD a dimension type to use for a target quantity
|
// * @tparam ToD a dimension type to use for a target quantity
|
||||||
* @tparam ToU a unit type to use for a target quantity
|
// * @tparam ToU a unit type to use for a target quantity
|
||||||
*/
|
// */
|
||||||
template<Dimension ToD, Unit ToU, typename O, typename U, typename Rep>
|
// template<Dimension ToD, Unit ToU, typename O, typename U, typename Rep>
|
||||||
requires equivalent<ToD, typename O::dimension> && UnitOf<ToU, ToD> && RebindablePointOriginFor<O, ToD>
|
// requires equivalent<ToD, typename O::dimension> && UnitOf<ToU, ToD> && RebindablePointOriginFor<O, ToD>
|
||||||
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<O, U, Rep>& q)
|
// [[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<O, U, Rep>& q)
|
||||||
{
|
// {
|
||||||
return quantity_point_cast<quantity_point<rebind_point_origin_dimension<O, ToD>, ToU, Rep>>(q);
|
// return quantity_point_cast<quantity_point<rebind_point_origin_dimension<O, ToD>, ToU, Rep>>(q);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @brief Explicit cast of a quantity kind
|
// * @brief Explicit cast of a quantity kind
|
||||||
*
|
// *
|
||||||
* Implicit conversions between quantity kinds of different types are allowed only for "safe"
|
// * Implicit conversions between quantity kinds of different types are allowed only for "safe"
|
||||||
* (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||||
*
|
// *
|
||||||
* This cast gets the target (quantity) kind type to cast to or anything that works for quantity_cast. For example:
|
// * This cast gets the target (quantity) kind type to cast to or anything that works for quantity_cast. For example:
|
||||||
*
|
// *
|
||||||
* auto q1 = units::quantity_kind_cast<decltype(ns::width{1 * m})>(quantity_kind{ns::width{1 * mm});
|
// * auto q1 = units::quantity_kind_cast<decltype(ns::width{1 * m})>(quantity_kind{ns::width{1 * mm});
|
||||||
* auto q1 = units::quantity_kind_cast<ns::height_kind>(ns::width{1 * m});
|
// * auto q1 = units::quantity_kind_cast<ns::height_kind>(ns::width{1 * m});
|
||||||
* auto q1 = units::quantity_kind_cast<units::isq::si::length<units::isq::si::metre>>(ns::width{1 * mm});
|
// * auto q1 = units::quantity_kind_cast<units::isq::si::length<units::isq::si::metre>>(ns::width{1 * mm});
|
||||||
* auto q1 = units::quantity_kind_cast<units::isq::si::dim_acceleration>(ns::rate_of_climb{200 * Gal});
|
// * auto q1 = units::quantity_kind_cast<units::isq::si::dim_acceleration>(ns::rate_of_climb{200 * Gal});
|
||||||
* auto q1 = units::quantity_kind_cast<units::isq::si::metre>(ns::width{1 * mm});
|
// * auto q1 = units::quantity_kind_cast<units::isq::si::metre>(ns::width{1 * mm});
|
||||||
* auto q1 = units::quantity_kind_cast<int>(ns::width{1.0 * mm});
|
// * auto q1 = units::quantity_kind_cast<int>(ns::width{1.0 * mm});
|
||||||
*
|
// *
|
||||||
* @tparam CastSpec a target (quantity) kind type to cast to or anything that works for quantity_cast
|
// * @tparam CastSpec a target (quantity) kind type to cast to or anything that works for quantity_cast
|
||||||
*/
|
// */
|
||||||
template<typename CastSpec, typename K, typename U, typename Rep>
|
// template<typename CastSpec, typename K, typename U, typename Rep>
|
||||||
[[nodiscard]] constexpr QuantityKind auto quantity_kind_cast(const quantity_kind<K, U, Rep>& qk)
|
// [[nodiscard]] constexpr QuantityKind auto quantity_kind_cast(const quantity_kind<K, U, Rep>& qk)
|
||||||
requires requires {
|
// requires requires {
|
||||||
requires is_specialization_of<CastSpec, quantity_kind>;
|
// requires is_specialization_of<CastSpec, quantity_kind>;
|
||||||
requires requires { quantity_cast<typename CastSpec::quantity_type>(qk.common()); };
|
// requires requires { quantity_cast<typename CastSpec::quantity_type>(qk.common()); };
|
||||||
} || requires {
|
// } || requires {
|
||||||
requires Kind<CastSpec>;
|
// requires Kind<CastSpec>;
|
||||||
requires UnitOf<U, typename CastSpec::dimension>;
|
// requires UnitOf<U, typename CastSpec::dimension>;
|
||||||
} || requires { quantity_cast<CastSpec>(qk.common()); } // TODO: Simplify when Clang catches up.
|
// } || requires { quantity_cast<CastSpec>(qk.common()); } // TODO: Simplify when Clang catches up.
|
||||||
{
|
// {
|
||||||
if constexpr (is_specialization_of<CastSpec, quantity_kind>)
|
// if constexpr (is_specialization_of<CastSpec, quantity_kind>)
|
||||||
return CastSpec(quantity_cast<typename CastSpec::quantity_type>(qk.common()));
|
// return CastSpec(quantity_cast<typename CastSpec::quantity_type>(qk.common()));
|
||||||
else if constexpr (Kind<CastSpec>)
|
// else if constexpr (Kind<CastSpec>)
|
||||||
return quantity_kind<CastSpec, U, Rep>(qk.common());
|
// return quantity_kind<CastSpec, U, Rep>(qk.common());
|
||||||
else {
|
// else {
|
||||||
auto q{quantity_cast<CastSpec>(qk.common())};
|
// auto q{quantity_cast<CastSpec>(qk.common())};
|
||||||
using Q = decltype(q);
|
// using Q = decltype(q);
|
||||||
return quantity_kind<K, typename Q::unit, typename Q::rep>(static_cast<Q&&>(q));
|
// return quantity_kind<K, typename Q::unit, typename Q::rep>(static_cast<Q&&>(q));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @brief Explicit cast of a quantity kind
|
// * @brief Explicit cast of a quantity kind
|
||||||
*
|
// *
|
||||||
* Implicit conversions between quantity kinds of different types are allowed only for "safe"
|
// * Implicit conversions between quantity kinds of different types are allowed only for "safe"
|
||||||
* (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||||
*
|
// *
|
||||||
* This cast gets both the target kind and unit to cast to. For example:
|
// * This cast gets both the target kind and unit to cast to. For example:
|
||||||
*
|
// *
|
||||||
* auto q1 = units::quantity_kind_cast<ns::height_kind, units::isq::si::kilometre>(w);
|
// * auto q1 = units::quantity_kind_cast<ns::height_kind, units::isq::si::kilometre>(w);
|
||||||
*
|
// *
|
||||||
* @note This cast is especially useful when working with quantity kinds of unknown kind.
|
// * @note This cast is especially useful when working with quantity kinds of unknown kind.
|
||||||
*
|
// *
|
||||||
* @tparam ToK the kind type to use for the target quantity
|
// * @tparam ToK the kind type to use for the target quantity
|
||||||
* @tparam ToU the unit type to use for the target quantity
|
// * @tparam ToU the unit type to use for the target quantity
|
||||||
*/
|
// */
|
||||||
template<Kind ToK, Unit ToU, typename K, typename U, typename Rep>
|
// template<Kind ToK, Unit ToU, typename K, typename U, typename Rep>
|
||||||
requires equivalent<typename ToK::dimension, typename K::dimension> && UnitOf<ToU, typename ToK::dimension>
|
// requires equivalent<typename ToK::dimension, typename K::dimension> && UnitOf<ToU, typename ToK::dimension>
|
||||||
[[nodiscard]] constexpr QuantityKind auto quantity_kind_cast(const quantity_kind<K, U, Rep>& qk)
|
// [[nodiscard]] constexpr QuantityKind auto quantity_kind_cast(const quantity_kind<K, U, Rep>& qk)
|
||||||
{
|
// {
|
||||||
return quantity_kind_cast<quantity_kind<ToK, ToU, Rep>>(qk);
|
// return quantity_kind_cast<quantity_kind<ToK, ToU, Rep>>(qk);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @brief Explicit cast of a quantity point kind
|
// * @brief Explicit cast of a quantity point kind
|
||||||
*
|
// *
|
||||||
* Implicit conversions between quantity point kinds of different types are allowed only for "safe"
|
// * Implicit conversions between quantity point kinds of different types are allowed only for "safe"
|
||||||
* (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||||
*
|
// *
|
||||||
* This cast gets the target (quantity) point kind type to cast to or anything that works for quantity_kind_cast. For
|
// * This cast gets the target (quantity) point kind type to cast to or anything that works for quantity_kind_cast. For
|
||||||
* example:
|
// * example:
|
||||||
*
|
// *
|
||||||
* auto q1 = units::quantity_point_kind_cast<decltype(ns::x_coordinate{1 * m))>(ns::x_coordinate{1 * mm});
|
// * auto q1 = units::quantity_point_kind_cast<decltype(ns::x_coordinate{1 * m))>(ns::x_coordinate{1 * mm});
|
||||||
* auto q1 = units::quantity_point_kind_cast<decltype(ns::width{1 * m})>(ns::x_coordinate{1 * mm});
|
// * auto q1 = units::quantity_point_kind_cast<decltype(ns::width{1 * m})>(ns::x_coordinate{1 * mm});
|
||||||
* auto q1 = units::quantity_point_kind_cast<ns::y_coordinate_kind>(ns::x_coordinate{1 * m});
|
// * auto q1 = units::quantity_point_kind_cast<ns::y_coordinate_kind>(ns::x_coordinate{1 * m});
|
||||||
* auto q1 = units::quantity_point_kind_cast<ns::height_kind>(ns::x_coordinate{1 * m});
|
// * auto q1 = units::quantity_point_kind_cast<ns::height_kind>(ns::x_coordinate{1 * m});
|
||||||
* auto q1 = units::quantity_point_kind_cast<units::isq::si::length<units::isq::si::metre>>(ns::x_coordinate{1 * mm});
|
// * auto q1 = units::quantity_point_kind_cast<units::isq::si::length<units::isq::si::metre>>(ns::x_coordinate{1 *
|
||||||
* auto q1 = units::quantity_point_kind_cast<units::isq::si::dim_acceleration>(quantity_point_kind(ns::rate_of_climb{200
|
// mm});
|
||||||
* * Gal})); auto q1 = units::quantity_point_kind_cast<units::isq::si::metre>(ns::x_coordinate{1 * mm}); auto q1 =
|
// * auto q1 =
|
||||||
* units::quantity_point_kind_cast<int>(ns::x_coordinate{1.0 * mm});
|
// units::quantity_point_kind_cast<units::isq::si::dim_acceleration>(quantity_point_kind(ns::rate_of_climb{200
|
||||||
*
|
// * * Gal})); auto q1 = units::quantity_point_kind_cast<units::isq::si::metre>(ns::x_coordinate{1 * mm}); auto q1 =
|
||||||
* @tparam CastSpec a target (quantity) point kind type to cast to or anything that works for quantity_kind_cast
|
// * units::quantity_point_kind_cast<int>(ns::x_coordinate{1.0 * mm});
|
||||||
*/
|
// *
|
||||||
template<typename CastSpec, typename PK, typename U, typename Rep>
|
// * @tparam CastSpec a target (quantity) point kind type to cast to or anything that works for quantity_kind_cast
|
||||||
[[nodiscard]] constexpr QuantityPointKind auto quantity_point_kind_cast(const quantity_point_kind<PK, U, Rep>& qpk)
|
// */
|
||||||
requires requires {
|
// template<typename CastSpec, typename PK, typename U, typename Rep>
|
||||||
requires is_specialization_of<CastSpec, quantity_point_kind>;
|
// [[nodiscard]] constexpr QuantityPointKind auto quantity_point_kind_cast(const quantity_point_kind<PK, U, Rep>& qpk)
|
||||||
requires requires { quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()); };
|
// requires requires {
|
||||||
requires equivalent<typename PK::origin, typename CastSpec::point_kind_type::origin>;
|
// requires is_specialization_of<CastSpec, quantity_point_kind>;
|
||||||
} || requires { requires PointKind<CastSpec> && UnitOf<U, typename CastSpec::dimension>; } ||
|
// requires requires { quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()); };
|
||||||
requires { quantity_kind_cast<CastSpec>(qpk.relative()); } // TODO: Simplify when Clang catches up.
|
// requires equivalent<typename PK::origin, typename CastSpec::point_kind_type::origin>;
|
||||||
{
|
// } || requires { requires PointKind<CastSpec> && UnitOf<U, typename CastSpec::dimension>; } ||
|
||||||
if constexpr (is_specialization_of<CastSpec, quantity_point_kind>)
|
// requires { quantity_kind_cast<CastSpec>(qpk.relative()); } // TODO: Simplify when Clang catches up.
|
||||||
return CastSpec(quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()));
|
// {
|
||||||
else if constexpr (PointKind<CastSpec>)
|
// if constexpr (is_specialization_of<CastSpec, quantity_point_kind>)
|
||||||
return quantity_point_kind(quantity_kind_cast<typename CastSpec::base_kind>(qpk.relative()));
|
// return CastSpec(quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()));
|
||||||
else
|
// else if constexpr (PointKind<CastSpec>)
|
||||||
return quantity_point_kind(quantity_kind_cast<CastSpec>(qpk.relative()));
|
// return quantity_point_kind(quantity_kind_cast<typename CastSpec::base_kind>(qpk.relative()));
|
||||||
}
|
// else
|
||||||
|
// return quantity_point_kind(quantity_kind_cast<CastSpec>(qpk.relative()));
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @brief Explicit cast of a quantity point kind
|
// * @brief Explicit cast of a quantity point kind
|
||||||
*
|
// *
|
||||||
* Implicit conversions between quantity point kinds of different types are allowed only for "safe"
|
// * Implicit conversions between quantity point kinds of different types are allowed only for "safe"
|
||||||
* (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||||
*
|
// *
|
||||||
* This cast gets both the target point kind and unit to cast to. For example:
|
// * This cast gets both the target point kind and unit to cast to. For example:
|
||||||
*
|
// *
|
||||||
* auto q1 = units::quantity_point_kind_cast<ns::y_coordinate_kind, units::isq::si::kilometre>(x);
|
// * auto q1 = units::quantity_point_kind_cast<ns::y_coordinate_kind, units::isq::si::kilometre>(x);
|
||||||
*
|
// *
|
||||||
* @note This cast is especially useful when working with quantity point kinds of unknown point kind.
|
// * @note This cast is especially useful when working with quantity point kinds of unknown point kind.
|
||||||
*
|
// *
|
||||||
* @tparam ToPK the point kind type to use for the target quantity
|
// * @tparam ToPK the point kind type to use for the target quantity
|
||||||
* @tparam ToU the unit type to use for the target quantity
|
// * @tparam ToU the unit type to use for the target quantity
|
||||||
*/
|
// */
|
||||||
template<PointKind ToPK, Unit ToU, typename PK, typename U, typename Rep>
|
// template<PointKind ToPK, Unit ToU, typename PK, typename U, typename Rep>
|
||||||
requires equivalent<typename ToPK::dimension, typename PK::dimension> && UnitOf<ToU, typename ToPK::dimension>
|
// requires equivalent<typename ToPK::dimension, typename PK::dimension> && UnitOf<ToU, typename ToPK::dimension>
|
||||||
[[nodiscard]] constexpr QuantityPointKind auto quantity_point_kind_cast(const quantity_point_kind<PK, U, Rep>& qpk)
|
// [[nodiscard]] constexpr QuantityPointKind auto quantity_point_kind_cast(const quantity_point_kind<PK, U, Rep>& qpk)
|
||||||
{
|
// {
|
||||||
return quantity_point_kind_cast<quantity_point_kind<ToPK, ToU, Rep>>(qpk);
|
// return quantity_point_kind_cast<quantity_point_kind<ToPK, ToU, Rep>>(qpk);
|
||||||
}
|
// }
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
|
||||||
|
@@ -136,13 +136,27 @@ template<Representation Rep, Reference R>
|
|||||||
|
|
||||||
void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, Reference auto) = delete;
|
void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, Reference auto) = delete;
|
||||||
|
|
||||||
|
template<Reference R1, Reference R2>
|
||||||
|
[[nodiscard]] consteval bool equivalent(R1, R2)
|
||||||
|
{
|
||||||
|
return equivalent(R1::dimension, R2::dimension) && equivalent(R1::unit, R2::unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Reference R1, Reference R2>
|
||||||
|
[[nodiscard]] consteval bool convertible(R1, R2)
|
||||||
|
{
|
||||||
|
return convertible(R1::dimension, R2::dimension) && convertible(R1::unit, R2::unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<Dimension auto Dim, Unit auto CoU>
|
template<Dimension auto Dim, Unit auto CoU>
|
||||||
struct system_reference {
|
struct system_reference {
|
||||||
static constexpr auto dimension = Dim;
|
static constexpr auto dimension = Dim;
|
||||||
static constexpr auto coherent_unit = CoU;
|
static constexpr auto coherent_unit = CoU;
|
||||||
|
|
||||||
template<Unit U>
|
template<Unit U>
|
||||||
// requires same_unit_reference<CoU, U>
|
// TODO enable that
|
||||||
|
// requires(convertible(coherent_unit, U{}))
|
||||||
[[nodiscard]] constexpr reference<std::remove_const_t<decltype(dimension)>, U> operator[](U) const
|
[[nodiscard]] constexpr reference<std::remove_const_t<decltype(dimension)>, U> operator[](U) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
@@ -153,3 +167,20 @@ inline constexpr struct dimensionless : system_reference<one_dim, one> {
|
|||||||
} dimensionless;
|
} dimensionless;
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template<units::Reference R1, units::Reference R2>
|
||||||
|
requires requires {
|
||||||
|
typename common_type_t<remove_const_t<decltype(R1::dimension)>, remove_const_t<decltype(R2::dimension)>>;
|
||||||
|
typename common_type_t<remove_const_t<decltype(R1::unit)>, remove_const_t<decltype(R2::unit)>>;
|
||||||
|
}
|
||||||
|
struct common_type<R1, R2> {
|
||||||
|
private:
|
||||||
|
using dim = common_type_t<remove_const_t<decltype(R1::dimension)>, remove_const_t<decltype(R2::dimension)>>;
|
||||||
|
using unit = common_type_t<remove_const_t<decltype(R1::unit)>, remove_const_t<decltype(R2::unit)>>;
|
||||||
|
public:
|
||||||
|
using type = units::reference<dim, unit>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
@@ -330,12 +330,6 @@ template<Unit U1, Unit U2>
|
|||||||
return is_same_v<U1, U2>;
|
return is_same_v<U1, U2>;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Unit U1, Unit U2>
|
|
||||||
[[nodiscard]] consteval bool equivalent(U1, U2)
|
|
||||||
{
|
|
||||||
return true; // TODO implement this
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// template<BaseDimension D1, BaseDimension D2>
|
// template<BaseDimension D1, BaseDimension D2>
|
||||||
// constexpr bool operator==(D1, D2)
|
// constexpr bool operator==(D1, D2)
|
||||||
@@ -366,6 +360,20 @@ template<Unit U1, Unit U2>
|
|||||||
// std::is_same_v<typename D1::normalized_den, typename D2::normalized_den>;
|
// std::is_same_v<typename D1::normalized_den, typename D2::normalized_den>;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// TODO implement this
|
||||||
|
// template<Dimension D1, Dimension D2>
|
||||||
|
// [[nodiscard]] consteval bool equivalent(D1, D2)
|
||||||
|
// {
|
||||||
|
// return is_same_v<detail::dim_type<D1>, detail::dim_type<D2>>;
|
||||||
|
// }
|
||||||
|
|
||||||
|
template<Unit U1, Unit U2>
|
||||||
|
[[nodiscard]] consteval bool convertible(U1, U2)
|
||||||
|
{
|
||||||
|
// TODO implement this
|
||||||
|
return std::derived_from<U1, U2> || std::derived_from<U2, U1>;
|
||||||
|
}
|
||||||
|
|
||||||
template<Unit U>
|
template<Unit U>
|
||||||
struct square_ : decltype(U{} * U{}) {};
|
struct square_ : decltype(U{} * U{}) {};
|
||||||
|
|
||||||
@@ -379,3 +387,15 @@ template<Unit auto U>
|
|||||||
inline constexpr cubic_<std::remove_const_t<decltype(U)>> cubic;
|
inline constexpr cubic_<std::remove_const_t<decltype(U)>> cubic;
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
// TODO implement this
|
||||||
|
template<units::Unit U1, units::Unit U2>
|
||||||
|
requires(units::convertible(U1{}, U2{}))
|
||||||
|
struct common_type<U1, U2> {
|
||||||
|
using type = ::units::conditional<std::derived_from<std::remove_const_t<U1>, std::remove_const_t<U2>>,
|
||||||
|
std::remove_const_t<U1>, std::remove_const_t<U2>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
@@ -36,14 +36,14 @@ inline constexpr struct length_dim_ : base_dimension<"L"> {} length_dim;
|
|||||||
inline constexpr struct time_dim_ : base_dimension<"T"> {} time_dim;
|
inline constexpr struct time_dim_ : base_dimension<"T"> {} time_dim;
|
||||||
|
|
||||||
inline constexpr struct frequency_dim_ : decltype(1 / time_dim) {} frequency_dim;
|
inline constexpr struct frequency_dim_ : decltype(1 / time_dim) {} frequency_dim;
|
||||||
|
inline constexpr struct action_dim_ : decltype(1 / time_dim) {} action_dim;
|
||||||
inline constexpr struct area_dim_ : decltype(length_dim * length_dim) {} area_dim;
|
inline constexpr struct area_dim_ : decltype(length_dim * length_dim) {} area_dim;
|
||||||
inline constexpr struct volume_dim_ : decltype(area_dim * length_dim) {} volume_dim;
|
inline constexpr struct volume_dim_ : decltype(area_dim * length_dim) {} volume_dim;
|
||||||
inline constexpr struct speed_dim_ : decltype(length_dim / time_dim) {} speed_dim;
|
inline constexpr struct speed_dim_ : decltype(length_dim / time_dim) {} speed_dim;
|
||||||
|
inline constexpr struct velocity_dim_ : speed_dim_ {} velocity_dim;
|
||||||
inline constexpr struct acceleration_dim_ : decltype(speed_dim / time_dim) {} acceleration_dim;
|
inline constexpr struct acceleration_dim_ : decltype(speed_dim / time_dim) {} acceleration_dim;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// concepts verification
|
// concepts verification
|
||||||
static_assert(BaseDimension<length_dim_>);
|
static_assert(BaseDimension<length_dim_>);
|
||||||
static_assert(!BaseDimension<frequency_dim_>);
|
static_assert(!BaseDimension<frequency_dim_>);
|
||||||
@@ -107,13 +107,19 @@ static_assert(length_dim / length_dim == one_dim);
|
|||||||
|
|
||||||
static_assert(1 / time_dim != frequency_dim);
|
static_assert(1 / time_dim != frequency_dim);
|
||||||
static_assert(equivalent(1 / time_dim, frequency_dim));
|
static_assert(equivalent(1 / time_dim, frequency_dim));
|
||||||
|
static_assert(convertible(1 / time_dim, frequency_dim));
|
||||||
static_assert(1 / frequency_dim == time_dim);
|
static_assert(1 / frequency_dim == time_dim);
|
||||||
static_assert(frequency_dim * time_dim == one_dim);
|
static_assert(frequency_dim * time_dim == one_dim);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(1 / time_dim), decltype(frequency_dim)>, frequency_dim_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(frequency_dim), decltype(1 / time_dim)>, frequency_dim_>);
|
||||||
|
|
||||||
static_assert(length_dim * length_dim != area_dim);
|
static_assert(length_dim * length_dim != area_dim);
|
||||||
static_assert(equivalent(length_dim * length_dim, area_dim));
|
static_assert(equivalent(length_dim * length_dim, area_dim));
|
||||||
|
static_assert(convertible(length_dim * length_dim, area_dim));
|
||||||
static_assert(length_dim * length_dim != volume_dim);
|
static_assert(length_dim * length_dim != volume_dim);
|
||||||
static_assert(area_dim / length_dim == length_dim);
|
static_assert(area_dim / length_dim == length_dim);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(length_dim * length_dim), decltype(area_dim)>, area_dim_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(area_dim), decltype(length_dim * length_dim)>, area_dim_>);
|
||||||
|
|
||||||
static_assert(length_dim * length_dim * length_dim != volume_dim);
|
static_assert(length_dim * length_dim * length_dim != volume_dim);
|
||||||
static_assert(equivalent(length_dim * length_dim * length_dim, volume_dim));
|
static_assert(equivalent(length_dim * length_dim * length_dim, volume_dim));
|
||||||
@@ -134,6 +140,10 @@ static_assert(length_dim * time_dim != speed_dim);
|
|||||||
static_assert(length_dim / time_dim / time_dim != speed_dim);
|
static_assert(length_dim / time_dim / time_dim != speed_dim);
|
||||||
static_assert(length_dim / speed_dim == time_dim);
|
static_assert(length_dim / speed_dim == time_dim);
|
||||||
static_assert(speed_dim * time_dim == length_dim);
|
static_assert(speed_dim * time_dim == length_dim);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(length_dim / time_dim), decltype(speed_dim)>, speed_dim_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(speed_dim), decltype(length_dim / time_dim)>, speed_dim_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(length_dim / time_dim), decltype(length_dim / time_dim)>,
|
||||||
|
decltype(length_dim / time_dim)>);
|
||||||
|
|
||||||
static_assert(length_dim / time_dim / time_dim != acceleration_dim);
|
static_assert(length_dim / time_dim / time_dim != acceleration_dim);
|
||||||
static_assert(equivalent(length_dim / time_dim / time_dim, acceleration_dim));
|
static_assert(equivalent(length_dim / time_dim / time_dim, acceleration_dim));
|
||||||
@@ -147,3 +157,21 @@ static_assert(equivalent(acceleration_dim * time_dim, speed_dim));
|
|||||||
static_assert(acceleration_dim * (time_dim * time_dim) == length_dim);
|
static_assert(acceleration_dim * (time_dim * time_dim) == length_dim);
|
||||||
static_assert(acceleration_dim / speed_dim != frequency_dim);
|
static_assert(acceleration_dim / speed_dim != frequency_dim);
|
||||||
static_assert(equivalent(acceleration_dim / speed_dim, frequency_dim));
|
static_assert(equivalent(acceleration_dim / speed_dim, frequency_dim));
|
||||||
|
|
||||||
|
static_assert(frequency_dim != action_dim);
|
||||||
|
static_assert(equivalent(frequency_dim, action_dim));
|
||||||
|
static_assert(!convertible(frequency_dim, action_dim));
|
||||||
|
template<auto T1, auto T2>
|
||||||
|
concept no_common_type = requires {
|
||||||
|
requires !requires { typename std::common_type_t<decltype(T1), decltype(T2)>; };
|
||||||
|
requires !requires { typename std::common_type_t<decltype(T2), decltype(T1)>; };
|
||||||
|
};
|
||||||
|
static_assert(no_common_type<frequency_dim, action_dim>);
|
||||||
|
|
||||||
|
static_assert(velocity_dim != speed_dim);
|
||||||
|
static_assert(equivalent(velocity_dim, speed_dim));
|
||||||
|
static_assert(convertible(speed_dim, velocity_dim));
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(velocity_dim), decltype(speed_dim)>, velocity_dim_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(speed_dim), decltype(velocity_dim)>, velocity_dim_>);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
Reference in New Issue
Block a user