mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-31 19:04:27 +02:00
feat: full-on dimensional analysis between related quantity kinds
This commit is contained in:
committed by
Mateusz Pusz
parent
dad9b4f166
commit
017183653d
@@ -49,6 +49,7 @@ set(unitsSphinxDocs
|
|||||||
"${CMAKE_CURRENT_SOURCE_DIR}/design/directories.rst"
|
"${CMAKE_CURRENT_SOURCE_DIR}/design/directories.rst"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/design/downcasting.rst"
|
"${CMAKE_CURRENT_SOURCE_DIR}/design/downcasting.rst"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/design/quantity.rst"
|
"${CMAKE_CURRENT_SOURCE_DIR}/design/quantity.rst"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/design/quantity_kind.rst"
|
||||||
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/examples.rst"
|
"${CMAKE_CURRENT_SOURCE_DIR}/examples.rst"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/examples/avg_speed.rst"
|
"${CMAKE_CURRENT_SOURCE_DIR}/examples/avg_speed.rst"
|
||||||
|
52
docs/design/quantity_kind.rst
Normal file
52
docs/design/quantity_kind.rst
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
.. namespace:: units
|
||||||
|
|
||||||
|
quantity_kind
|
||||||
|
=============
|
||||||
|
|
||||||
|
The ``quantity_kind`` class template provides a similar interface to ``quantity``.
|
||||||
|
|
||||||
|
Kinds
|
||||||
|
-----
|
||||||
|
|
||||||
|
The first template parameter of ``quantity_kind`` is a ``Kind``.
|
||||||
|
|
||||||
|
``Kind``s, by themselves:
|
||||||
|
|
||||||
|
* Wrap a ``Dimension``, and
|
||||||
|
* opt into the downcasting facility.
|
||||||
|
|
||||||
|
If a dimensional analysis operator on a quantity of kind *A*
|
||||||
|
can result on a quantity of kind *B*,
|
||||||
|
*A* and *B* are *related*.
|
||||||
|
|
||||||
|
The library provides two ``Kind`` bases, ``kind`` and ``derived_kind``.
|
||||||
|
|
||||||
|
``kind`` is an entry point, and there's only one per set of related kinds.
|
||||||
|
|
||||||
|
``derived_kind`` is used to explicitly name other related kinds.
|
||||||
|
Unnamed, they look like ``detail::_kind_base<the-entry-kind, some_dimension>``.
|
||||||
|
|
||||||
|
Unnamed kinds, like unnamed units and dimensions,
|
||||||
|
allows (intermediate) results in formulas without having to name them.
|
||||||
|
|
||||||
|
Quantity kinds
|
||||||
|
--------------
|
||||||
|
|
||||||
|
``quantity_kind`` wraps a ``quantity`` and layers over its dimensional analysis.
|
||||||
|
While all properties of the ``quantity`` apply transparently,
|
||||||
|
results are always ``quantity_kind``s related to the kind(s) of the argument(s).
|
||||||
|
|
||||||
|
One of the arguments to the dimensional analysis operators can also be ``Quantity``.
|
||||||
|
|
||||||
|
The way back to ``quantity`` is through the ``.common()`` observer.
|
||||||
|
|
||||||
|
Intra-kind operations
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
``quantity_kind`` takes care of operators between related quantity kinds.
|
||||||
|
Intra-kind operations can be opted into as follows::
|
||||||
|
|
||||||
|
struct width : kind<width, dim_length> {};
|
||||||
|
struct height : kind<height, dim_length> {};
|
||||||
|
|
||||||
|
size2d operator+(QuantityKindOf<width> auto, QuantityKindOf<height> auto);
|
@@ -67,23 +67,40 @@ dimension, than we will end up with just a dimensionless quantity:
|
|||||||
Quantity Kinds
|
Quantity Kinds
|
||||||
++++++++++++++
|
++++++++++++++
|
||||||
|
|
||||||
Quantity kinds behave the same as quantities for addition and subtraction.
|
Quantity kinds behave the same as quantities for all operations,
|
||||||
The same behavior is also provided for multiplication with, and division by
|
except that the quantity types in the operators' declarations
|
||||||
a :term:`scalable number`.
|
are quantity kind types instead.
|
||||||
|
Additionally, for the dimensional analysis operators,
|
||||||
Multiplication and division with a quantity (but not a quantity kind) is allowed.
|
you can use a quantity argument instead of a quantity kind.
|
||||||
The result is a quantity kind with the appropriate dimension
|
|
||||||
and related to the original quantity kind:
|
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
:emphasize-lines: 5-6
|
:emphasize-lines: 8-9
|
||||||
|
|
||||||
struct height : kind<height, dim_length> {};
|
struct height_kind : kind<height_kind, dim_length> {};
|
||||||
struct rate_of_climb : derived_kind<rate_of_climb, height, dim_speed> {};
|
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, height_kind, dim_speed> {};
|
||||||
|
|
||||||
quantity_kind h(height{}, 100 * m);
|
template <Unit U, QuantityValue Rep = double> using height = quantity_kind<height_kind, U, Rep>;
|
||||||
quantity_point_kind rate = h / (25 * s);
|
template <Unit U, QuantityValue Rep = double> using rate_of_climb = quantity_kind<rate_of_climb_kind, U, Rep>;
|
||||||
// quantity_point_kind<rate_of_climb, si::metre_per_second, int>(4 * m / s)
|
|
||||||
|
height h{100 * m};
|
||||||
|
rate_of_climb rate = h / (25 * s);
|
||||||
|
// quantity_kind<rate_of_climb_kind, si::metre_per_second, int>(4 * m / s)
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
:emphasize-lines: 8-12
|
||||||
|
|
||||||
|
struct width_kind : kind<width_kind, dim_length> {};
|
||||||
|
struct horizontal_area_kind : derived_kind<horizontal_area_kind, width_kind, dim_area> {};
|
||||||
|
|
||||||
|
template <Unit U, QuantityValue Rep = double> using width = quantity_kind<width_kind, U, Rep>;
|
||||||
|
template <Unit U, QuantityValue Rep = double> using horizontal_area = quantity_kind<horizontal_area_kind, U, Rep>;
|
||||||
|
|
||||||
|
width w{5 * m};
|
||||||
|
horizontal_area area1 = w * w;
|
||||||
|
// quantity_kind<horizontal_area_kind, si::metre_per_second, int>(25 * m * m)
|
||||||
|
width w2 = area1 / w; // quantity_kind<width_kind, si::metre, int>(5 * m)
|
||||||
|
auto q1 = w / w; // Dimensionless quantity kinds related to width
|
||||||
|
auto q2 = w / (5 * m); // with .common() equal to quantity{1}
|
||||||
|
|
||||||
Quantity Points
|
Quantity Points
|
||||||
+++++++++++++++
|
+++++++++++++++
|
||||||
|
@@ -41,7 +41,7 @@ the value to the `quantity_kind` class template constructor::
|
|||||||
Differences To Quantity
|
Differences To Quantity
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Unlike `quantity`, the library provides:
|
The library provides:
|
||||||
|
|
||||||
- no kinds, such as ``radius`` or ``width``, therefore
|
- no kinds, such as ``radius`` or ``width``, therefore
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ Unlike `quantity`, the library provides:
|
|||||||
* no kind-specific concepts, such as ``Radius``,
|
* no kind-specific concepts, such as ``Radius``,
|
||||||
(there's the generic `QuantityKind` and kind-specifiable `QuantityKindOf`),
|
(there's the generic `QuantityKind` and kind-specifiable `QuantityKindOf`),
|
||||||
|
|
||||||
- a slightly different set of operations on quantity kinds
|
- a slightly larger set of operations on quantity kinds
|
||||||
(see the :ref:`framework/dimensions:Quantity Kinds` chapter).
|
(see the :ref:`framework/dimensions:Quantity Kinds` chapter).
|
||||||
|
|
||||||
|
|
||||||
|
@@ -100,8 +100,8 @@ using namespace si::international::literals;
|
|||||||
using namespace si::unit_constants;
|
using namespace si::unit_constants;
|
||||||
|
|
||||||
template<QuantityKind QK1, QuantityKind QK2>
|
template<QuantityKind QK1, QuantityKind QK2>
|
||||||
constexpr Quantity auto operator/(const QK1& lhs, const QK2& rhs)
|
constexpr Dimensionless auto operator/(const QK1& lhs, const QK2& rhs)
|
||||||
requires requires { lhs.common() / rhs.common(); } {
|
requires (!units::QuantityKindRelatedTo<QK1, QK2>) && requires { lhs.common() / rhs.common(); } {
|
||||||
return lhs.common() / rhs.common();
|
return lhs.common() / rhs.common();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +258,7 @@ struct flight_point {
|
|||||||
constexpr altitude terrain_level_alt(const task& t, distance dist)
|
constexpr altitude terrain_level_alt(const task& t, distance dist)
|
||||||
{
|
{
|
||||||
const height alt_diff = t.finish.alt - t.start.alt;
|
const height alt_diff = t.finish.alt - t.start.alt;
|
||||||
return t.start.alt + alt_diff * (dist / t.dist);
|
return t.start.alt + alt_diff * (dist / t.dist).common();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr height agl(altitude glider_alt, altitude terrain_level)
|
constexpr height agl(altitude glider_alt, altitude terrain_level)
|
||||||
@@ -283,7 +283,7 @@ void print(std::string_view phase_name, const flight_point& point, const flight_
|
|||||||
|
|
||||||
flight_point tow(const flight_point& point, const aircraft_tow& at)
|
flight_point tow(const flight_point& point, const aircraft_tow& at)
|
||||||
{
|
{
|
||||||
const duration d = at.height_agl / at.performance;
|
const duration d = (at.height_agl / at.performance).common();
|
||||||
const flight_point new_point{point.dur + d, point.dist, point.alt + at.height_agl};
|
const flight_point new_point{point.dur + d, point.dist, point.alt + at.height_agl};
|
||||||
|
|
||||||
print("Tow", point, new_point);
|
print("Tow", point, new_point);
|
||||||
@@ -295,7 +295,7 @@ flight_point circle(const flight_point& point, const glider& g, const weather& w
|
|||||||
const height h_agl = agl(point.alt, terrain_level_alt(t, point.dist));
|
const height h_agl = agl(point.alt, terrain_level_alt(t, point.dist));
|
||||||
const height circle_height = std::min(w.cloud_base - h_agl, height_to_gain);
|
const height circle_height = std::min(w.cloud_base - h_agl, height_to_gain);
|
||||||
const rate_of_climb circling_rate = w.thermal_strength + g.polar[0].climb;
|
const rate_of_climb circling_rate = w.thermal_strength + g.polar[0].climb;
|
||||||
const duration d = circle_height / circling_rate;
|
const duration d = (circle_height / circling_rate).common();
|
||||||
const flight_point new_point{point.dur + d, point.dist, point.alt + circle_height};
|
const flight_point new_point{point.dur + d, point.dist, point.alt + circle_height};
|
||||||
|
|
||||||
height_to_gain -= circle_height;
|
height_to_gain -= circle_height;
|
||||||
|
@@ -246,6 +246,16 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Rep2>
|
||||||
|
constexpr quantity& operator%=(const dimensionless<units::one, Rep2>& rhs)
|
||||||
|
requires (!floating_point_<rep>) && (!floating_point_<Rep2>) &&
|
||||||
|
requires(rep a, const Rep2 b) { { a %= b } -> std::same_as<rep&>; }
|
||||||
|
{
|
||||||
|
gsl_ExpectsAudit(rhs.count() != quantity_values<Rep2>::zero());
|
||||||
|
value_ %= rhs.count();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr quantity& operator%=(const quantity& q)
|
constexpr quantity& operator%=(const quantity& q)
|
||||||
requires (!floating_point_<rep>) &&
|
requires (!floating_point_<rep>) &&
|
||||||
requires(rep a, rep b) { { a %= b } -> std::same_as<rep&>; }
|
requires(rep a, rep b) { { a %= b } -> std::same_as<rep&>; }
|
||||||
|
@@ -53,6 +53,15 @@ inline constexpr auto& downcasted_kind = downcasted_kind_fn<typename QK::kind_ty
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching two related quantity kinds
|
||||||
|
*
|
||||||
|
* Satisfied by quantity kinds having equivalent base kinds.
|
||||||
|
*/
|
||||||
|
template<typename QK1, typename QK2>
|
||||||
|
concept QuantityKindRelatedTo = QuantityKind<QK1> && QuantityKind<QK2> &&
|
||||||
|
equivalent<typename QK1::kind_type::base_kind, typename QK2::kind_type::base_kind>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A quantity kind
|
* @brief A quantity kind
|
||||||
*
|
*
|
||||||
@@ -180,6 +189,13 @@ public:
|
|||||||
q_ *= rhs;
|
q_ *= rhs;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
template<typename Rep2>
|
||||||
|
constexpr quantity_kind& operator*=(const quantity_kind<downcast_kind<K, dim_one>, units::one, Rep2>& rhs)
|
||||||
|
requires requires(quantity_type q) { q *= rhs.common(); }
|
||||||
|
{
|
||||||
|
q_ *= rhs.common();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Rep2>
|
template<typename Rep2>
|
||||||
constexpr quantity_kind& operator/=(const Rep2& rhs)
|
constexpr quantity_kind& operator/=(const Rep2& rhs)
|
||||||
@@ -189,15 +205,29 @@ public:
|
|||||||
q_ /= rhs;
|
q_ /= rhs;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
template<typename Rep2>
|
||||||
|
constexpr quantity_kind& operator/=(const quantity_kind<downcast_kind<K, dim_one>, units::one, Rep2>& rhs)
|
||||||
|
requires requires(quantity_type q) { q /= rhs.common(); }
|
||||||
|
{
|
||||||
|
q_ /= rhs.common();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Rep2>
|
template<typename Rep2>
|
||||||
constexpr quantity_kind& operator%=(const Rep2& rhs)
|
constexpr quantity_kind& operator%=(const Rep2& rhs)
|
||||||
requires (!Quantity<Rep2>) && requires(quantity_type q, const Rep2 r) { q %= r; }
|
requires (!Quantity<Rep2> || Dimensionless<Rep2>) && requires(quantity_type q, const Rep2 r) { q %= r; }
|
||||||
{
|
{
|
||||||
gsl_ExpectsAudit(rhs != quantity_values<Rep2>::zero());
|
gsl_ExpectsAudit(rhs != quantity_values<Rep2>::zero());
|
||||||
q_ %= rhs;
|
q_ %= rhs;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
template<typename Rep2>
|
||||||
|
constexpr quantity_kind& operator%=(const quantity_kind<downcast_kind<K, dim_one>, units::one, Rep2>& rhs)
|
||||||
|
requires requires(quantity_type q) { q %= rhs.common(); }
|
||||||
|
{
|
||||||
|
q_ %= rhs.common();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr quantity_kind& operator%=(const quantity_kind& qk)
|
constexpr quantity_kind& operator%=(const quantity_kind& qk)
|
||||||
requires requires(quantity_type q) { q %= qk.common(); }
|
requires requires(quantity_type q) { q %= qk.common(); }
|
||||||
@@ -256,9 +286,6 @@ public:
|
|||||||
[[nodiscard]] friend constexpr bool operator==(const quantity_kind&, const quantity_kind&) = default;
|
[[nodiscard]] friend constexpr bool operator==(const quantity_kind&, const quantity_kind&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<Kind K, QuantityValue V>
|
|
||||||
explicit(false) quantity_kind(K, V) -> quantity_kind<K, one, V>;
|
|
||||||
|
|
||||||
template<QuantityKind QK1, QuantityKindEquivalentTo<QK1> QK2>
|
template<QuantityKind QK1, QuantityKindEquivalentTo<QK1> QK2>
|
||||||
[[nodiscard]] constexpr QuantityKind auto operator+(const QK1& lhs, const QK2& rhs)
|
[[nodiscard]] constexpr QuantityKind auto operator+(const QK1& lhs, const QK2& rhs)
|
||||||
requires requires { lhs.common() + rhs.common(); }
|
requires requires { lhs.common() + rhs.common(); }
|
||||||
@@ -287,6 +314,13 @@ template<Quantity Q, QuantityKind QK>
|
|||||||
return detail::downcasted_kind<QK>(lhs * rhs.common());
|
return detail::downcasted_kind<QK>(lhs * rhs.common());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<QuantityKind QK1, QuantityKindRelatedTo<QK1> QK2>
|
||||||
|
[[nodiscard]] constexpr QuantityKind auto operator*(const QK1& lhs, const QK2& rhs)
|
||||||
|
requires requires { lhs.common() * rhs.common(); }
|
||||||
|
{
|
||||||
|
return detail::downcasted_kind<QK1>(lhs.common() * rhs.common());
|
||||||
|
}
|
||||||
|
|
||||||
template<QuantityKind QK, Quantity Q>
|
template<QuantityKind QK, Quantity Q>
|
||||||
[[nodiscard]] constexpr QuantityKind auto operator/(const QK& lhs, const Q& rhs)
|
[[nodiscard]] constexpr QuantityKind auto operator/(const QK& lhs, const Q& rhs)
|
||||||
requires requires { lhs.common() / rhs; }
|
requires requires { lhs.common() / rhs; }
|
||||||
@@ -303,6 +337,13 @@ template<Quantity Q, QuantityKind QK>
|
|||||||
return detail::downcasted_kind<QK>(lhs / rhs.common());
|
return detail::downcasted_kind<QK>(lhs / rhs.common());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<QuantityKind QK1, QuantityKindRelatedTo<QK1> QK2>
|
||||||
|
[[nodiscard]] constexpr QuantityKind auto operator/(const QK1& lhs, const QK2& rhs)
|
||||||
|
requires requires { lhs.common() / rhs.common(); }
|
||||||
|
{
|
||||||
|
return detail::downcasted_kind<QK1>(lhs.common() / rhs.common());
|
||||||
|
}
|
||||||
|
|
||||||
template<QuantityKind QK, Dimensionless D>
|
template<QuantityKind QK, Dimensionless D>
|
||||||
[[nodiscard]] constexpr QuantityKind auto operator%(const QK& lhs, const D& rhs)
|
[[nodiscard]] constexpr QuantityKind auto operator%(const QK& lhs, const D& rhs)
|
||||||
requires requires { lhs.common() % rhs; }
|
requires requires { lhs.common() % rhs; }
|
||||||
|
@@ -182,9 +182,6 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<PointKind PK, QuantityValue V>
|
|
||||||
explicit(false) quantity_point_kind(PK, V) -> quantity_point_kind<PK, one, V>;
|
|
||||||
|
|
||||||
template<QuantityKind QK>
|
template<QuantityKind QK>
|
||||||
quantity_point_kind(QK) ->
|
quantity_point_kind(QK) ->
|
||||||
quantity_point_kind<downcast_point_kind<typename QK::kind_type>, typename QK::unit, typename QK::rep>;
|
quantity_point_kind<downcast_point_kind<typename QK::kind_type>, typename QK::unit, typename QK::rep>;
|
||||||
|
@@ -309,6 +309,7 @@ static_assert(construct_from_only<width<cgs::centimetre, double>>(1.0 * cm).comm
|
|||||||
static_assert(construct_and_convert_from<width<metre, int>>(width<metre, int>(1 * m)).common() == 1 * m);
|
static_assert(construct_and_convert_from<width<metre, int>>(width<metre, int>(1 * m)).common() == 1 * m);
|
||||||
static_assert(construct_and_convert_from<width<centimetre, int>>(width<cgs::centimetre, int>(1 * cgs_cm)).common() == 1 * cm);
|
static_assert(construct_and_convert_from<width<centimetre, int>>(width<cgs::centimetre, int>(1 * cgs_cm)).common() == 1 * cm);
|
||||||
static_assert(construct_and_convert_from<width<fps::foot, double>>(width<cgs::centimetre, int>(1 * cgs_cm)).common() == 1 * cm);
|
static_assert(construct_and_convert_from<width<fps::foot, double>>(width<cgs::centimetre, int>(1 * cgs_cm)).common() == 1 * cm);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
static_assert(construct_and_convert_from<width<metre, double>>(width<metre, int>(1 * m)).common() == 1 * m);
|
static_assert(construct_and_convert_from<width<metre, double>>(width<metre, int>(1 * m)).common() == 1 * m);
|
||||||
static_assert(!constructible_or_convertible_from<width<metre, int>>(width<metre, double>(1.0 * m)));
|
static_assert(!constructible_or_convertible_from<width<metre, int>>(width<metre, double>(1.0 * m)));
|
||||||
@@ -322,7 +323,6 @@ static_assert(construct_and_convert_from<width<kilometre, double>>(width<metre,
|
|||||||
static_assert(!constructible_or_convertible_from<width<metre, int>>(height<metre, int>(1 * m)));
|
static_assert(!constructible_or_convertible_from<width<metre, int>>(height<metre, int>(1 * m)));
|
||||||
static_assert(!constructible_or_convertible_from<apples<one, int>>(width<metre, int>(1 * m) / m));
|
static_assert(!constructible_or_convertible_from<apples<one, int>>(width<metre, int>(1 * m) / m));
|
||||||
static_assert(!constructible_or_convertible_from<apples<one, int>>(oranges<one, int>(1)));
|
static_assert(!constructible_or_convertible_from<apples<one, int>>(oranges<one, int>(1)));
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
@@ -380,23 +380,42 @@ static_assert([]() {
|
|||||||
assert(&(w -= w) == &w && w.common() == 0 * m);
|
assert(&(w -= w) == &w && w.common() == 0 * m);
|
||||||
w = width<metre, int>(3 * m);
|
w = width<metre, int>(3 * m);
|
||||||
assert(&(w *= 3) == &w && w.common() == 9 * m);
|
assert(&(w *= 3) == &w && w.common() == 9 * m);
|
||||||
|
assert(&(w *= quantity(1)) == &w && w.common() == 9 * m);
|
||||||
|
assert(&(w *= (w / w)) == &w && w.common() == 9 * m);
|
||||||
assert(&(w /= 2) == &w && w.common() == 4 * m);
|
assert(&(w /= 2) == &w && w.common() == 4 * m);
|
||||||
|
assert(&(w /= quantity(1)) == &w && w.common() == 4 * m);
|
||||||
|
assert(&(w /= (w / w)) == &w && w.common() == 4 * m);
|
||||||
assert(&(w %= 3) == &w && w.common() == 1 * m);
|
assert(&(w %= 3) == &w && w.common() == 1 * m);
|
||||||
|
assert(&(w %= quantity(3)) == &w && w.common() == 1 * m);
|
||||||
|
assert(&(w %= 3 * (w / w)) == &w && w.common() == 1 * m);
|
||||||
assert(&(w %= w) == &w && w.common() == 0 * m);
|
assert(&(w %= w) == &w && w.common() == 0 * m);
|
||||||
w = width<metre, int>(3 * m);
|
w = width<metre, int>(3 * m);
|
||||||
assert(&(w *= 3.9) == &w && w.common() == 11 * m);
|
assert(&(w *= 3.9) == &w && w.common() == 11 * m);
|
||||||
|
assert(&(w *= quantity(1.0)) == &w && w.common() == 11 * m);
|
||||||
|
assert(&(w *= 1.0 * (w / w)) == &w && w.common() == 11 * m);
|
||||||
assert(&(w /= 3.9) == &w && w.common() == 2 * m);
|
assert(&(w /= 3.9) == &w && w.common() == 2 * m);
|
||||||
|
assert(&(w /= quantity(1.0)) == &w && w.common() == 2 * m);
|
||||||
|
assert(&(w /= 1.0 * (w / w)) == &w && w.common() == 2 * m);
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static_assert((std::uint8_t(255) * m %= 256) == (width<metre, std::uint8_t>(255 * m) %= 256).common());
|
static_assert((std::uint8_t(255) * m %= 256) == (width<metre, std::uint8_t>(255 * m) %= 256).common());
|
||||||
|
static_assert((std::uint8_t(255) * m %= quantity(256)) ==
|
||||||
|
(width<metre, std::uint8_t>(255 * m) %= quantity(256)).common());
|
||||||
|
// static_assert((std::uint8_t(255) * m %= 256 * m) ==
|
||||||
|
// (width<metre, std::uint8_t>(255 * m) %=
|
||||||
|
// quantity_kind<downcast_kind<width_kind, dim_one>, one, std::uint8_t>(256)).common()); // UB
|
||||||
// static_assert((std::uint8_t(255) * m %= 256 * m) !=
|
// static_assert((std::uint8_t(255) * m %= 256 * m) !=
|
||||||
// (width<metre, std::uint8_t>(255 * m) %= width<metre, std::uint8_t>(256 * m)).common()); // UB
|
// (width<metre, std::uint8_t>(255 * m) %= width<metre, std::uint8_t>(256 * m)).common()); // UB
|
||||||
static_assert((std::uint8_t(255) * m %= 257) == (width<metre, std::uint8_t>(255 * m) %= 257).common());
|
static_assert((std::uint8_t(255) * m %= 257) == (width<metre, std::uint8_t>(255 * m) %= 257).common());
|
||||||
// TODO: Fix
|
static_assert((std::uint8_t(255) * m %= quantity(257)) ==
|
||||||
|
(width<metre, std::uint8_t>(255 * m) %= quantity(257)).common());
|
||||||
static_assert((std::uint8_t(255) * m %= 257 * m) ==
|
static_assert((std::uint8_t(255) * m %= 257 * m) ==
|
||||||
(width<metre, std::uint8_t>(255 * m) %= width<metre, std::uint8_t>(257 * m)).common());
|
(width<metre, std::uint8_t>(255 * m) %=
|
||||||
|
quantity_kind<downcast_kind<width_kind, dim_one>, one, std::uint8_t>(257)).common());
|
||||||
|
static_assert((std::uint8_t(255) * m %= 257 * m) ==
|
||||||
|
(width<metre, std::uint8_t>(255 * m) %= width<metre, std::uint8_t>(257 * m)).common());
|
||||||
|
|
||||||
static_assert(same((-width<metre, short>(short{1} * m)).common(), int{-1} * m));
|
static_assert(same((-width<metre, short>(short{1} * m)).common(), int{-1} * m));
|
||||||
|
|
||||||
@@ -409,11 +428,20 @@ concept invalid_compound_assignments_ = requires(quantity_kind<K, U, int> w, Qx
|
|||||||
requires !requires { w %= q; };
|
requires !requires { w %= q; };
|
||||||
};
|
};
|
||||||
template<typename Width>
|
template<typename Width>
|
||||||
concept invalid_compound_assignments = requires(quantity_kind<Width, metre, int> w) {
|
concept invalid_compound_assignments = requires(quantity_kind<Width, metre, int> w, height<metre, int> h) {
|
||||||
requires !requires { w += 1; };
|
requires !requires { w += 1; };
|
||||||
requires !requires { w -= 1; };
|
requires !requires { w -= 1; };
|
||||||
|
requires !requires { w *= 1 * km / m; };
|
||||||
|
requires !requires { w /= 1 * km / m; };
|
||||||
|
requires !requires { w %= 1 * km / m; };
|
||||||
|
requires !requires { w *= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<ratio{1, 1, 3}, one>, int>{1}; };
|
||||||
|
requires !requires { w /= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<ratio{1, 1, 3}, one>, int>{1}; };
|
||||||
|
requires !requires { w %= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<ratio{1, 1, 3}, one>, int>{1}; };
|
||||||
requires !requires { w %= 1.0; };
|
requires !requires { w %= 1.0; };
|
||||||
requires !requires { w %= w * 1.0; };
|
requires !requires { w %= quantity(1.0); };
|
||||||
|
requires !requires { w %= 1.0 * (w / w); };
|
||||||
|
requires !requires { w %= 1.0 * w; };
|
||||||
|
requires !requires { w %= h / h; };
|
||||||
requires invalid_compound_assignments_<Width, metre, length<metre, int>>;
|
requires invalid_compound_assignments_<Width, metre, length<metre, int>>;
|
||||||
requires invalid_compound_assignments_<Width, metre, height<metre, int>>;
|
requires invalid_compound_assignments_<Width, metre, height<metre, int>>;
|
||||||
requires invalid_compound_assignments_<Width, metre, horizontal_area<square_metre, int>>;
|
requires invalid_compound_assignments_<Width, metre, horizontal_area<square_metre, int>>;
|
||||||
@@ -477,6 +505,26 @@ static_assert(same(2 * width<metre, int>(3 * m), width<metre, int>(6 * m)));
|
|||||||
static_assert(same(2 * width<metre, double>(3. * m), width<metre, double>(6. * m)));
|
static_assert(same(2 * width<metre, double>(3. * m), width<metre, double>(6. * m)));
|
||||||
static_assert(same(2. * width<metre, int>(3 * m), width<metre, double>(6. * m)));
|
static_assert(same(2. * width<metre, int>(3 * m), width<metre, double>(6. * m)));
|
||||||
|
|
||||||
|
static_assert(same(width<metre, int>(2 * m) * quantity(3), width<metre, int>(6 * m)));
|
||||||
|
static_assert(same(width<metre, int>(2 * m) * quantity(3.), width<metre, double>(6. * m)));
|
||||||
|
static_assert(same(width<metre, double>(2. * m) * quantity(3), width<metre, double>(6. * m)));
|
||||||
|
static_assert(same(quantity(2) * width<metre, int>(3 * m), width<metre, int>(6 * m)));
|
||||||
|
static_assert(same(quantity(2) * width<metre, double>(3. * m), width<metre, double>(6. * m)));
|
||||||
|
static_assert(same(quantity(2.) * width<metre, int>(3 * m), width<metre, double>(6. * m)));
|
||||||
|
|
||||||
|
static_assert(same(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
|
||||||
|
width<metre, int>(6 * m)));
|
||||||
|
static_assert(same(width<metre, int>(2 * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3.),
|
||||||
|
width<metre, double>(6. * m)));
|
||||||
|
static_assert(same(width<metre, double>(2. * m) * quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
|
||||||
|
width<metre, double>(6. * m)));
|
||||||
|
static_assert(same(quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(2) * width<metre, int>(3 * m),
|
||||||
|
width<metre, int>(6 * m)));
|
||||||
|
static_assert(same(quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(2) * width<metre, double>(3. * m),
|
||||||
|
width<metre, double>(6. * m)));
|
||||||
|
static_assert(same(quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(2.) * width<metre, int>(3 * m),
|
||||||
|
width<metre, double>(6. * m)));
|
||||||
|
|
||||||
static_assert(same(height<metre, int>(2 * m) * (3 * Hz), rate_of_climb<metre_per_second, int>(6 * m / s)));
|
static_assert(same(height<metre, int>(2 * m) * (3 * Hz), rate_of_climb<metre_per_second, int>(6 * m / s)));
|
||||||
static_assert(same(height<metre, int>(2 * m) * (3. * Hz), rate_of_climb<metre_per_second, double>(6. * m / s)));
|
static_assert(same(height<metre, int>(2 * m) * (3. * Hz), rate_of_climb<metre_per_second, double>(6. * m / s)));
|
||||||
static_assert(same(height<metre, double>(2. * m) * (3 * Hz), rate_of_climb<metre_per_second, double>(6. * m / s)));
|
static_assert(same(height<metre, double>(2. * m) * (3 * Hz), rate_of_climb<metre_per_second, double>(6. * m / s)));
|
||||||
@@ -484,13 +532,65 @@ static_assert(same((2 * Hz) * height<metre, int>(3 * m), rate_of_climb<metre_per
|
|||||||
static_assert(same((2 * Hz) * height<metre, double>(3. * m), rate_of_climb<metre_per_second, double>(6. * m / s)));
|
static_assert(same((2 * Hz) * height<metre, double>(3. * m), rate_of_climb<metre_per_second, double>(6. * m / s)));
|
||||||
static_assert(same((2. * Hz) * height<metre, int>(3 * m), rate_of_climb<metre_per_second, double>(6. * m / s)));
|
static_assert(same((2. * Hz) * height<metre, int>(3 * m), rate_of_climb<metre_per_second, double>(6. * m / s)));
|
||||||
|
|
||||||
|
static_assert(same(quantity_kind<time_kind, second, int>(2 * s) * (3 * Hz),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(6)));
|
||||||
|
static_assert(same((3 * Hz) * quantity_kind<time_kind, second, int>(2 * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(6)));
|
||||||
|
|
||||||
|
static_assert(same(apples<one, int>(2) * quantity(2), apples<one, int>(4)));
|
||||||
|
static_assert(same(quantity(2) * apples<one, int>(2), apples<one, int>(4)));
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
static_assert(same(width<metre, int>(2 * m) * width<metre, int>(2 * m), horizontal_area<square_metre, int>(4 * m * m)));
|
||||||
|
static_assert(same(width<metre, int>(2 * m) * width<metre, double>(2 * m), horizontal_area<square_metre, double>(4 * m * m)));
|
||||||
|
static_assert(same(width<metre, double>(2 * m) * width<metre, int>(2 * m), horizontal_area<square_metre, double>(4 * m * m)));
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static_assert(same(apples<one, int>(2) * apples<one, int>(2), apples<one, int>(4)));
|
||||||
|
static_assert(same(apples<one, int>(2) * (2 / apples<one, int>(1)), apples<one, int>(4)));
|
||||||
|
|
||||||
|
static_assert(same(width<kilometre>(2 * m) * width<millimetre>(2 * m), horizontal_area<square_metre>(4 * m * m)));
|
||||||
|
static_assert(same(width<metre>(2 * m) * (1 / width<metre>(2 * m)),
|
||||||
|
quantity_kind<downcast_kind<width_kind, dim_one>, one>(1)));
|
||||||
|
|
||||||
static_assert(same(width<metre, int>(2 * m) / 3, width<metre, int>(0 * m)));
|
static_assert(same(width<metre, int>(2 * m) / 3, width<metre, int>(0 * m)));
|
||||||
static_assert(same(width<metre, int>(2 * m) / 3., width<metre, double>(2 / 3. * m)));
|
static_assert(same(width<metre, int>(2 * m) / 3., width<metre, double>(2 / 3. * m)));
|
||||||
static_assert(same(width<metre, double>(2. * m) / 3, width<metre, double>(2. / 3 * m)));
|
static_assert(same(width<metre, double>(2. * m) / 3, width<metre, double>(2. / 3 * m)));
|
||||||
|
|
||||||
static_assert(same((2 / width<metre, int>(3 * m)).common(), 2 / 3 / m));
|
static_assert(same(width<metre, int>(2 * m) / quantity(3), width<metre, int>(0 * m)));
|
||||||
static_assert(same((2 / width<metre, double>(3. * m)).common(), 2 / 3. / m));
|
static_assert(same(width<metre, int>(2 * m) / quantity(3.), width<metre, double>(2 / 3. * m)));
|
||||||
static_assert(same((2. / width<metre, int>(3 * m)).common(), 2. / 3 / m));
|
static_assert(same(width<metre, double>(2. * m) / quantity(3), width<metre, double>(2. / 3 * m)));
|
||||||
|
|
||||||
|
static_assert(same(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(3),
|
||||||
|
width<metre, int>(0 * m)));
|
||||||
|
static_assert(same(width<metre, int>(2 * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3.),
|
||||||
|
width<metre, double>(2 / 3. * m)));
|
||||||
|
static_assert(same(width<metre, double>(2. * m) / quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(3),
|
||||||
|
width<metre, double>(2. / 3 * m)));
|
||||||
|
|
||||||
|
static_assert(same(2 / quantity_kind<time_kind, second, int>(3 * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / s)));
|
||||||
|
static_assert(same(2 / quantity_kind<time_kind, second, double>(3. * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
|
||||||
|
static_assert(same(2. / quantity_kind<time_kind, second, int>(3 * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
|
||||||
|
|
||||||
|
static_assert(same(quantity(2) / quantity_kind<time_kind, second, int>(3 * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / s)));
|
||||||
|
static_assert(same(quantity(2) / quantity_kind<time_kind, second, double>(3. * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
|
||||||
|
static_assert(same(quantity(2.) / quantity_kind<time_kind, second, int>(3 * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(2) / quantity_kind<time_kind, second, int>(3 * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / s)));
|
||||||
|
static_assert(
|
||||||
|
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(2) / quantity_kind<time_kind, second, double>(3. * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
|
||||||
|
static_assert(
|
||||||
|
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, double>(2.) / quantity_kind<time_kind, second, int>(3 * s),
|
||||||
|
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
|
||||||
|
|
||||||
static_assert(same(height<metre, int>(2 * m) / (3 * s), rate_of_climb<metre_per_second, int>(0 * m / s)));
|
static_assert(same(height<metre, int>(2 * m) / (3 * s), rate_of_climb<metre_per_second, int>(0 * m / s)));
|
||||||
static_assert(same(height<metre, int>(2 * m) / (3. * s), rate_of_climb<metre_per_second, double>(2 / 3. * m / s)));
|
static_assert(same(height<metre, int>(2 * m) / (3. * s), rate_of_climb<metre_per_second, double>(2 / 3. * m / s)));
|
||||||
@@ -501,11 +601,31 @@ static_assert(same(dimensionless<percent, int>(2) * width<metre, int>(3 * m), wi
|
|||||||
static_assert(same(width<metre, int>(2 * m) / dimensionless<percent, double>(3), width<hectometre, double>(2. / 3 * hm)));
|
static_assert(same(width<metre, int>(2 * m) / dimensionless<percent, double>(3), width<hectometre, double>(2. / 3 * hm)));
|
||||||
static_assert(same(width<metre, int>(2 * m) % dimensionless<percent, int>(3), width<centimetre, int>(2 * cm)));
|
static_assert(same(width<metre, int>(2 * m) % dimensionless<percent, int>(3), width<centimetre, int>(2 * cm)));
|
||||||
|
|
||||||
static_assert(same(((2 * m) / height<metre, int>(3 * m)), quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0)));
|
static_assert(same(height<metre, int>(2 * m) / (3 * m),
|
||||||
static_assert(same(((2 * m) / height<metre, int>(3 * m)).common(), quantity(0)));
|
quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0)));
|
||||||
static_assert(same(((2 * m) / height<metre, double>(3. * m)).common(), quantity(2 / 3.)));
|
static_assert(same(height<metre, int>(2 * m) / (3. * m),
|
||||||
static_assert(same(((2. * m) / height<metre, int>(3 * m)).common(), quantity(2. / 3)));
|
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2 / 3.)));
|
||||||
static_assert(same(((2 * m) / height<metre, int>(3 * m) * (0 * m)), height<metre, int>(0 * m)));
|
static_assert(same(height<metre, double>(2. * m) / (3 * m),
|
||||||
|
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2. / 3)));
|
||||||
|
|
||||||
|
static_assert(same((2 * m) / height<metre, int>(3 * m),
|
||||||
|
quantity_kind<downcast_kind<height_kind, dim_one>, one, int>(0)));
|
||||||
|
static_assert(same((2 * m) / height<metre, double>(3. * m),
|
||||||
|
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2 / 3.)));
|
||||||
|
static_assert(same((2. * m) / height<metre, int>(3 * m),
|
||||||
|
quantity_kind<downcast_kind<height_kind, dim_one>, one, double>(2. / 3)));
|
||||||
|
|
||||||
|
static_assert(same(width<metre, int>(8 * m) / width<metre, int>(2 * m),
|
||||||
|
quantity_kind<downcast_kind<width_kind, dim_one>, one, int>(4)));
|
||||||
|
static_assert(same(width<metre, int>(8 * m) / width<metre, double>(2 * m),
|
||||||
|
quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(4.0)));
|
||||||
|
static_assert(same(width<metre, double>(8 * m) / width<metre, int>(2 * m),
|
||||||
|
quantity_kind<downcast_kind<width_kind, dim_one>, one, double>(4.0)));
|
||||||
|
|
||||||
|
static_assert(same(apples<one, int>(8) / apples<one, int>(2), apples<one, int>(4)));
|
||||||
|
static_assert(same(apples<one, int>(8) / (2 / apples<one, int>(1)), apples<one, int>(4)));
|
||||||
|
|
||||||
|
static_assert(same(horizontal_area<square_metre>(8 * m * m) / width<metre>(2 * m), width<metre>(4 * m)));
|
||||||
|
|
||||||
static_assert(same(width<metre, int>(2 * m) % 3, width<metre, int>(2 * m)));
|
static_assert(same(width<metre, int>(2 * m) % 3, width<metre, int>(2 * m)));
|
||||||
static_assert(same(width<metre, int>(3 * m) % width<metre, int>(2 * m), width<metre, int>(1 * m)));
|
static_assert(same(width<metre, int>(3 * m) % width<metre, int>(2 * m), width<metre, int>(1 * m)));
|
||||||
@@ -514,7 +634,6 @@ static_assert(is_same_v<
|
|||||||
decltype((width<metre, std::uint8_t>(0 * m) % width<metre, std::uint8_t>(0 * m)).common().count()),
|
decltype((width<metre, std::uint8_t>(0 * m) % width<metre, std::uint8_t>(0 * m)).common().count()),
|
||||||
decltype(std::uint8_t(0) % std::uint8_t(0))>);
|
decltype(std::uint8_t(0) % std::uint8_t(0))>);
|
||||||
|
|
||||||
static_assert(!std::is_invocable_v<std::multiplies<>, width<metre>, width<metre>>);
|
|
||||||
static_assert(!std::is_invocable_v<std::multiplies<>, width<metre>, height<metre>>);
|
static_assert(!std::is_invocable_v<std::multiplies<>, width<metre>, height<metre>>);
|
||||||
static_assert(!std::is_invocable_v<std::multiplies<>, height<metre>, quantity_point<dim_length, metre>>);
|
static_assert(!std::is_invocable_v<std::multiplies<>, height<metre>, quantity_point<dim_length, metre>>);
|
||||||
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_point<dim_length, metre>, height<metre>>);
|
static_assert(!std::is_invocable_v<std::multiplies<>, quantity_point<dim_length, metre>, height<metre>>);
|
||||||
|
@@ -336,7 +336,6 @@ static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(apples
|
|||||||
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(apples<percent, double>(dimensionless<percent>(1))));
|
static_assert(!constructible_or_convertible_from<nth_apple<percent, int>>(apples<percent, double>(dimensionless<percent>(1))));
|
||||||
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(apples<one, double>(1.0)));
|
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(apples<one, double>(1.0)));
|
||||||
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(apples<percent, double>(dimensionless<percent>(1))));
|
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(apples<percent, double>(dimensionless<percent>(1))));
|
||||||
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(width<metre, int>(1 * m) / m));
|
|
||||||
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(oranges<one, int>(1)));
|
static_assert(!constructible_or_convertible_from<nth_apple<one, int>>(oranges<one, int>(1)));
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
@@ -278,9 +278,10 @@ static_assert((1_q_m += 1_q_m).count() == 2);
|
|||||||
static_assert((2_q_m -= 1_q_m).count() == 1);
|
static_assert((2_q_m -= 1_q_m).count() == 1);
|
||||||
static_assert((1_q_m *= 2).count() == 2);
|
static_assert((1_q_m *= 2).count() == 2);
|
||||||
static_assert((2_q_m /= 2).count() == 1);
|
static_assert((2_q_m /= 2).count() == 1);
|
||||||
|
static_assert((7_q_m %= 2).count() == 1);
|
||||||
static_assert((1_q_m *= quantity(2)).count() == 2);
|
static_assert((1_q_m *= quantity(2)).count() == 2);
|
||||||
static_assert((2_q_m /= quantity(2)).count() == 1);
|
static_assert((2_q_m /= quantity(2)).count() == 1);
|
||||||
static_assert((7_q_m %= 2).count() == 1);
|
static_assert((7_q_m %= quantity(2)).count() == 1);
|
||||||
static_assert((7_q_m %= 2_q_m).count() == 1);
|
static_assert((7_q_m %= 2_q_m).count() == 1);
|
||||||
|
|
||||||
// different types
|
// different types
|
||||||
@@ -295,8 +296,10 @@ static_assert((7.5_q_m /= quantity(3)).count() == 2.5);
|
|||||||
static_assert((3500_q_m %= 1_q_km).count() == 500);
|
static_assert((3500_q_m %= 1_q_km).count() == 500);
|
||||||
|
|
||||||
static_assert((std::uint8_t(255) * m %= 256).count() == [] { std::uint8_t ui(255); return ui %= 256; }());
|
static_assert((std::uint8_t(255) * m %= 256).count() == [] { std::uint8_t ui(255); return ui %= 256; }());
|
||||||
|
static_assert((std::uint8_t(255) * m %= quantity(256)).count() == [] { std::uint8_t ui(255); return ui %= 256; }());
|
||||||
// static_assert((std::uint8_t(255) * m %= 256 * m).count() != [] { std::uint8_t ui(255); return ui %= 256; }()); // UB
|
// static_assert((std::uint8_t(255) * m %= 256 * m).count() != [] { std::uint8_t ui(255); return ui %= 256; }()); // UB
|
||||||
static_assert((std::uint8_t(255) * m %= 257).count() == [] { std::uint8_t ui(255); return ui %= 257; }());
|
static_assert((std::uint8_t(255) * m %= 257).count() == [] { std::uint8_t ui(255); return ui %= 257; }());
|
||||||
|
static_assert((std::uint8_t(255) * m %= quantity(257)).count() == [] { std::uint8_t ui(255); return ui %= 257; }());
|
||||||
// TODO: Fix
|
// TODO: Fix
|
||||||
static_assert((std::uint8_t(255) * m %= 257 * m).count() != [] { std::uint8_t ui(255); return ui %= 257; }());
|
static_assert((std::uint8_t(255) * m %= 257 * m).count() != [] { std::uint8_t ui(255); return ui %= 257; }());
|
||||||
|
|
||||||
@@ -309,14 +312,21 @@ static_assert((22_q_m *= quantity(33.33)).count() == 733);
|
|||||||
static_assert((22_q_m /= quantity(3.33)).count() == 6);
|
static_assert((22_q_m /= quantity(3.33)).count() == 6);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename Metre>
|
template<typename Metre, typename Kilometre>
|
||||||
concept invalid_compound_assignments = requires() {
|
concept invalid_compound_assignments = requires() {
|
||||||
// truncating not allowed
|
// truncating not allowed
|
||||||
requires !requires(length<Metre, int> l) { l += 2.5_q_m; };
|
requires !requires(length<Metre, int> l) { l += 2.5_q_m; };
|
||||||
requires !requires(length<Metre, int> l) { l -= 2.5_q_m; };
|
requires !requires(length<Metre, int> l) { l -= 2.5_q_m; };
|
||||||
requires !requires(length<kilometre, int> l) { l += length<Metre, int>(2); };
|
requires !requires(length<Kilometre, int> l) { l += length<Metre, int>(2); };
|
||||||
requires !requires(length<kilometre, int> l) { l -= length<Metre, int>(2); };
|
requires !requires(length<Kilometre, int> l) { l -= length<Metre, int>(2); };
|
||||||
requires !requires(length<kilometre, int> l) { l %= length<Metre, int>(2); };
|
requires !requires(length<Kilometre, int> l) { l %= length<Metre, int>(2); };
|
||||||
|
requires !requires(length<Kilometre, int> l) { l %= dimensionless<percent, int>(2); };
|
||||||
|
requires !requires(length<Kilometre, int> l) { l %= dimensionless<percent, double>(2); };
|
||||||
|
|
||||||
|
// TODO: accept non-truncating argument
|
||||||
|
requires !requires(length<Kilometre, int> l) { l *= 1 * km / m; };
|
||||||
|
requires !requires(length<Kilometre, int> l) { l /= 1 * km / m; };
|
||||||
|
requires !requires(length<Kilometre, int> l) { l %= 1 * km / m; };
|
||||||
|
|
||||||
// only quantities can be added or subtracted
|
// only quantities can be added or subtracted
|
||||||
requires !requires(length<Metre, int> l) { l += 2; };
|
requires !requires(length<Metre, int> l) { l += 2; };
|
||||||
@@ -333,7 +343,7 @@ concept invalid_compound_assignments = requires() {
|
|||||||
requires !requires(length<Metre, double> l) { l %= 2_q_m; };
|
requires !requires(length<Metre, double> l) { l %= 2_q_m; };
|
||||||
requires !requires(length<Metre, int> l) { l %= 2._q_m; };
|
requires !requires(length<Metre, int> l) { l %= 2._q_m; };
|
||||||
};
|
};
|
||||||
static_assert(invalid_compound_assignments<metre>);
|
static_assert(invalid_compound_assignments<metre, kilometre>);
|
||||||
|
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
|
Reference in New Issue
Block a user