mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-31 02:47:16 +02:00
Merge branch 'master' into unit_compose_ext
This commit is contained in:
@ -125,6 +125,30 @@ all the properties of scaled units and is consistent with the rest of the librar
|
||||
[the Dimensionless Quantities chapter](../users_guide/framework_basics/dimensionless_quantities.md).
|
||||
|
||||
|
||||
## Why do the identifiers for concepts in the library use `CamelCase`?
|
||||
|
||||
Initially, C++20 was meant to use `CamelCase` for all the concept identifiers. All the concepts
|
||||
from the `std::ranges` library were merged with such names into the standard document draft.
|
||||
Frustratingly, `CamelCase` concepts got dropped from the C++ standard at the last moment before
|
||||
releasing C++20. Now, we are facing the predictable consequences of running out of names.
|
||||
|
||||
As long as some concepts in the library could be easily named with a `standard_case` there are
|
||||
some that are hard to distinguish from the corresponding type names, such as `Quantity`,
|
||||
`QuantityPoint`, `QuantitySpec`, or `Reference`. This is why we decided to use `CamelCase`
|
||||
consistently for all the concept identifiers to make it clear when we are talking about a type
|
||||
or concept identifier.
|
||||
|
||||
However, we are aware that this might be a temporary solution. In case the library gets
|
||||
standardized, we can expect the ISO C++ Committee to bikeshed/rename all of
|
||||
the concept identifiers to a `standard_case`, even if it will result in a harder to understand
|
||||
code.
|
||||
|
||||
!!! note
|
||||
|
||||
In case you have a good idea on how to rename [existing concepts](../users_guide/framework_basics/basic_concepts.md)
|
||||
to the `standard_case`, please let us know in the associated [GitHub Issue]().
|
||||
|
||||
|
||||
## Why Unicode quantity symbols are used by default instead of ASCII-only characters?
|
||||
|
||||
Both C++ and [ISO 80000](../appendix/references.md#ISO80000) are standardized by the ISO.
|
||||
|
@ -427,7 +427,12 @@ for which an instantiation of `quantity_like_traits` type trait yields a valid t
|
||||
- Static data member `reference` that matches the [`Reference`](#Reference) concept,
|
||||
- `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided
|
||||
in `reference`,
|
||||
- `value(T)` static member function returning a raw value of the quantity.
|
||||
- `to_numerical_value(T)` static member function returning a raw value of the quantity packed in
|
||||
either `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in
|
||||
the latter case,
|
||||
- `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly`
|
||||
or `convert_implicitly` wrapper that enables implicit conversion in the latter case.
|
||||
|
||||
|
||||
??? abstract "Examples"
|
||||
|
||||
@ -438,10 +443,20 @@ for which an instantiation of `quantity_like_traits` type trait yields a valid t
|
||||
struct mp_units::quantity_like_traits<std::chrono::seconds> {
|
||||
static constexpr auto reference = si::second;
|
||||
using rep = std::chrono::seconds::rep;
|
||||
[[nodiscard]] static constexpr rep value(const std::chrono::seconds& q) { return q.count(); }
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<rep> to_numerical_value(const std::chrono::seconds& q)
|
||||
{
|
||||
return q.count();
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<std::chrono::seconds> from_numerical_value(const rep& v)
|
||||
{
|
||||
return std::chrono::seconds(v);
|
||||
}
|
||||
};
|
||||
|
||||
quantity q(42s);
|
||||
quantity q = 42s;
|
||||
std::chrono::seconds dur = 42 * s;
|
||||
```
|
||||
|
||||
|
||||
@ -454,8 +469,13 @@ for which an instantiation of `quantity_point_like_traits` type trait yields a v
|
||||
- Static data member `point_origin` that matches the [`PointOrigin`](#PointOrigin) concept
|
||||
- `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided
|
||||
in `reference`
|
||||
- `quantity_from_origin(T)` static member function returning the `quantity` being the offset of the point
|
||||
from the origin
|
||||
- `to_quantity(T)` static member function returning the `quantity` being the offset of the point
|
||||
from the origin packed in either `convert_explicitly` or `convert_implicitly` wrapper that enables
|
||||
implicit conversion in the latter case,
|
||||
- `from_quantity(quantity<reference, rep>)` static member function returning `T` packed in either
|
||||
`convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in the latter
|
||||
case.
|
||||
|
||||
|
||||
??? abstract "Examples"
|
||||
|
||||
@ -464,14 +484,22 @@ for which an instantiation of `quantity_point_like_traits` type trait yields a v
|
||||
```cpp
|
||||
template<typename C>
|
||||
struct mp_units::quantity_point_like_traits<std::chrono::time_point<C, std::chrono::seconds>> {
|
||||
using T = std::chrono::time_point<C, std::chrono::seconds>;
|
||||
static constexpr auto reference = si::second;
|
||||
static constexpr auto point_origin = chrono_point_origin;
|
||||
static constexpr struct point_origin : absolute_point_origin<isq::time> {} point_origin{};
|
||||
using rep = std::chrono::seconds::rep;
|
||||
[[nodiscard]] static constexpr auto quantity_from_origin(const std::chrono::time_point<C, std::chrono::seconds>& qp)
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<quantity<reference, rep>> to_quantity(const T& qp)
|
||||
{
|
||||
return quantity{std::chrono::duration_cast<std::chrono::seconds>(qp.time_since_epoch())};
|
||||
return quantity{qp.time_since_epoch()};
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<T> from_quantity(const quantity<reference, rep>& q)
|
||||
{
|
||||
return T(q);
|
||||
}
|
||||
};
|
||||
|
||||
quantity_point qp(time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()));
|
||||
quantity_point qp = time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now());
|
||||
std::chrono::sys_seconds q = qp + 42 * s;
|
||||
```
|
||||
|
@ -79,7 +79,7 @@ using longitude = mp_units::quantity_point<mp_units::si::degree, prime_meridian,
|
||||
template<class CharT, class Traits, typename T>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const latitude<T>& lat)
|
||||
{
|
||||
if (is_gt_zero(lat))
|
||||
if (is_gteq_zero(lat))
|
||||
return os << lat.quantity_from_origin() << " N";
|
||||
else
|
||||
return os << -lat.quantity_from_origin() << " S";
|
||||
@ -88,7 +88,7 @@ std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>&
|
||||
template<class CharT, class Traits, typename T>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const longitude<T>& lon)
|
||||
{
|
||||
if (is_gt_zero(lon))
|
||||
if (is_gteq_zero(lon))
|
||||
return os << lon.quantity_from_origin() << " E";
|
||||
else
|
||||
return os << -lon.quantity_from_origin() << " W";
|
||||
@ -138,8 +138,8 @@ struct MP_UNITS_STD_FMT::formatter<geographic::latitude<T>> :
|
||||
auto format(geographic::latitude<T> lat, FormatContext& ctx)
|
||||
{
|
||||
formatter<typename geographic::latitude<T>::quantity_type>::format(
|
||||
is_gt_zero(lat) ? lat.quantity_from(geographic::equator) : -lat.quantity_from(geographic::equator), ctx);
|
||||
MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lat) ? " N" : "S");
|
||||
is_gteq_zero(lat) ? lat.quantity_from(geographic::equator) : -lat.quantity_from(geographic::equator), ctx);
|
||||
MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gteq_zero(lat) ? " N" : "S");
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
@ -151,9 +151,10 @@ struct MP_UNITS_STD_FMT::formatter<geographic::longitude<T>> :
|
||||
auto format(geographic::longitude<T> lon, FormatContext& ctx)
|
||||
{
|
||||
formatter<typename geographic::longitude<T>::quantity_type>::format(
|
||||
is_gt_zero(lon) ? lon.quantity_from(geographic::prime_meridian) : -lon.quantity_from(geographic::prime_meridian),
|
||||
is_gteq_zero(lon) ? lon.quantity_from(geographic::prime_meridian)
|
||||
: -lon.quantity_from(geographic::prime_meridian),
|
||||
ctx);
|
||||
MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lon) ? " E" : " W");
|
||||
MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gteq_zero(lon) ? " E" : " W");
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
@ -134,11 +134,11 @@ void example()
|
||||
using namespace mp_units;
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
|
||||
const auto a = isq::acceleration(measurement{9.8, 0.1} * m / s2);
|
||||
const auto t = measurement{1.2, 0.1} * s;
|
||||
const auto acceleration = isq::acceleration(measurement{9.8, 0.1} * m / s2);
|
||||
const auto time = measurement{1.2, 0.1} * s;
|
||||
|
||||
const QuantityOf<isq::velocity> auto v = a * t;
|
||||
std::cout << a << " * " << t << " = " << v << " = " << v.in(km / h) << '\n';
|
||||
const QuantityOf<isq::velocity> auto velocity = acceleration * time;
|
||||
std::cout << acceleration << " * " << time << " = " << velocity << " = " << velocity.in(km / h) << '\n';
|
||||
|
||||
const auto length = measurement{123., 1.} * m;
|
||||
std::cout << "10 * " << length << " = " << 10 * length << '\n';
|
||||
|
@ -103,9 +103,9 @@ struct width_checker {
|
||||
if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative width"));
|
||||
}
|
||||
return static_cast<unsigned long long>(value);
|
||||
} else {
|
||||
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer"));
|
||||
}
|
||||
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer"));
|
||||
return 0; // should never happen
|
||||
}
|
||||
};
|
||||
|
||||
@ -118,9 +118,9 @@ struct precision_checker {
|
||||
if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative precision"));
|
||||
}
|
||||
return static_cast<unsigned long long>(value);
|
||||
} else {
|
||||
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("precision is not integer"));
|
||||
}
|
||||
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("precision is not integer"));
|
||||
return 0; // should never happen
|
||||
}
|
||||
};
|
||||
|
||||
@ -230,6 +230,7 @@ template<std::input_iterator It, std::sentinel_for<It> S, typename IDHandler>
|
||||
return begin;
|
||||
}
|
||||
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("invalid format string"));
|
||||
return begin; // should never happen
|
||||
}
|
||||
|
||||
template<std::input_iterator It, std::sentinel_for<It> S, typename IDHandler>
|
||||
|
@ -58,8 +58,8 @@ template<QuantitySpec A, QuantitySpec B>
|
||||
template<QuantitySpec A, QuantitySpec B>
|
||||
[[nodiscard]] consteval auto have_common_base(A a, B b)
|
||||
{
|
||||
constexpr int a_length = hierarchy_path_length(A{});
|
||||
constexpr int b_length = hierarchy_path_length(B{});
|
||||
constexpr std::size_t a_length = hierarchy_path_length(A{});
|
||||
constexpr std::size_t b_length = hierarchy_path_length(B{});
|
||||
if constexpr (a_length > b_length)
|
||||
return have_common_base_in_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b);
|
||||
else
|
||||
|
@ -74,15 +74,19 @@ concept QuantityOf = Quantity<Q> && ReferenceOf<std::remove_const_t<decltype(Q::
|
||||
* all quantity-specific information.
|
||||
*/
|
||||
template<typename T>
|
||||
concept QuantityLike = requires(T q) {
|
||||
concept QuantityLike = requires {
|
||||
quantity_like_traits<T>::reference;
|
||||
requires Reference<std::remove_const_t<decltype(quantity_like_traits<T>::reference)>>;
|
||||
typename quantity_like_traits<T>::rep;
|
||||
requires RepresentationOf<typename quantity_like_traits<T>::rep,
|
||||
get_quantity_spec(quantity_like_traits<T>::reference).character>;
|
||||
} && requires(T q, typename quantity_like_traits<T>::rep v) {
|
||||
{
|
||||
make_quantity<quantity_like_traits<T>::reference>(quantity_like_traits<T>::value(q))
|
||||
} -> std::same_as<quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>>;
|
||||
quantity_like_traits<T>::to_numerical_value(q)
|
||||
} -> detail::ConversionSpecOf<typename quantity_like_traits<T>::rep>;
|
||||
{
|
||||
quantity_like_traits<T>::from_numerical_value(v)
|
||||
} -> detail::ConversionSpecOf<T>;
|
||||
};
|
||||
|
||||
} // namespace mp_units
|
||||
|
@ -173,7 +173,7 @@ concept QuantityPointOf =
|
||||
* all quantity_point-specific information.
|
||||
*/
|
||||
template<typename T>
|
||||
concept QuantityPointLike = requires(T qp) {
|
||||
concept QuantityPointLike = requires {
|
||||
quantity_point_like_traits<T>::reference;
|
||||
requires Reference<std::remove_const_t<decltype(quantity_point_like_traits<T>::reference)>>;
|
||||
quantity_point_like_traits<T>::point_origin;
|
||||
@ -181,13 +181,15 @@ concept QuantityPointLike = requires(T qp) {
|
||||
typename quantity_point_like_traits<T>::rep;
|
||||
requires RepresentationOf<typename quantity_point_like_traits<T>::rep,
|
||||
get_quantity_spec(quantity_point_like_traits<T>::reference).character>;
|
||||
requires Quantity<std::remove_cvref_t<decltype(quantity_point_like_traits<T>::quantity_from_origin(qp))>>;
|
||||
} && requires(T qp, quantity<quantity_point_like_traits<T>::reference, typename quantity_point_like_traits<T>::rep> q) {
|
||||
{
|
||||
make_quantity_point<quantity_point_like_traits<T>::point_origin>(
|
||||
quantity_point_like_traits<T>::quantity_from_origin(qp))
|
||||
}
|
||||
-> std::same_as<quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin,
|
||||
typename quantity_point_like_traits<T>::rep>>;
|
||||
quantity_point_like_traits<T>::to_quantity(qp)
|
||||
} -> detail::ConversionSpecOf<
|
||||
quantity<quantity_point_like_traits<T>::reference, typename quantity_point_like_traits<T>::rep>>;
|
||||
|
||||
{
|
||||
quantity_point_like_traits<T>::from_quantity(q)
|
||||
} -> detail::ConversionSpecOf<T>;
|
||||
};
|
||||
|
||||
} // namespace mp_units
|
||||
|
@ -132,11 +132,42 @@ struct quantity_values {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct convert_explicitly {
|
||||
using value_type = T;
|
||||
T value;
|
||||
constexpr explicit(false) convert_explicitly(T v) noexcept(std::is_nothrow_constructible_v<T>) : value(std::move(v))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct convert_implicitly {
|
||||
using value_type = T;
|
||||
T value;
|
||||
constexpr explicit(false) convert_implicitly(T v) noexcept(std::is_nothrow_constructible_v<T>) : value(std::move(v))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
concept ConversionSpec = is_specialization_of<T, convert_explicitly> || is_specialization_of<T, convert_implicitly>;
|
||||
|
||||
template<typename T, typename U>
|
||||
concept ConversionSpecOf = ConversionSpec<T> && std::same_as<typename T::value_type, U>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief Provides support for external quantity-like types
|
||||
*
|
||||
* The type trait should provide the @c reference object, a type alias @c rep,
|
||||
* and a static member function @c value(T) that returns the raw value of the quantity.
|
||||
* and static member functions @c to_numerical_value(T) that returns the raw value
|
||||
* of the quantity and @c from_numerical_value(rep) that returns @c T from @c rep.
|
||||
* Both return types should be encapsulated in either @c convert_explicitly or
|
||||
* @c convert_implicitly to specify if the conversion is allowed to happen implicitly.
|
||||
*
|
||||
* Usage example can be found in @c units/chrono.h header file.
|
||||
*
|
||||
@ -149,8 +180,11 @@ struct quantity_like_traits;
|
||||
* @brief Provides support for external quantity point-like types
|
||||
*
|
||||
* The type trait should provide nested @c reference and @c origin objects,
|
||||
* a type alias @c rep, and a static member function @c quantity_from_origin(T) that will
|
||||
* return the quantity being the offset of the point from the origin.
|
||||
* a type alias @c rep, and static member functions @c to_quantity(T) that returns
|
||||
* the quantity being the offset of the point from the origin and
|
||||
* @c from_quantity(quantity<reference, rep>) that returns @c T form this quantity.
|
||||
* Both return types should be encapsulated in either @c convert_explicitly or
|
||||
* @c convert_implicitly to specify if the conversion is allowed to happen implicitly.
|
||||
*
|
||||
* Usage example can be found in @c units/chrono.h header file.
|
||||
*
|
||||
|
@ -133,15 +133,17 @@ public:
|
||||
template<QuantityLike Q>
|
||||
requires detail::QuantityConvertibleTo<
|
||||
quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>, quantity>
|
||||
constexpr explicit quantity(const Q& q) :
|
||||
quantity(make_quantity<quantity_like_traits<Q>::reference>(quantity_like_traits<Q>::value(q)))
|
||||
constexpr explicit(is_specialization_of<decltype(quantity_like_traits<Q>::to_numerical_value(std::declval<Q>())),
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<typename Q::rep, Rep>) quantity(const Q& q) :
|
||||
quantity(make_quantity<quantity_like_traits<Q>::reference>(quantity_like_traits<Q>::to_numerical_value(q).value))
|
||||
{
|
||||
}
|
||||
|
||||
quantity& operator=(const quantity&) = default;
|
||||
quantity& operator=(quantity&&) = default;
|
||||
|
||||
// conversions
|
||||
// unit conversions
|
||||
template<UnitCompatibleWith<unit, quantity_spec> U>
|
||||
requires detail::QuantityConvertibleTo<quantity, quantity<detail::make_reference(quantity_spec, U{}), Rep>>
|
||||
[[nodiscard]] constexpr Quantity auto in(U) const
|
||||
@ -189,6 +191,31 @@ public:
|
||||
return (*this).force_in(U{}).numerical_value_;
|
||||
}
|
||||
|
||||
// conversion operators
|
||||
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>>
|
||||
requires detail::QuantityConvertibleTo<
|
||||
quantity, quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>>
|
||||
[[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(numerical_value_)),
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<Rep, typename Q::rep>) constexpr
|
||||
operator Q_() const& noexcept(noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_)) &&
|
||||
std::is_nothrow_copy_constructible_v<rep>)
|
||||
{
|
||||
return quantity_like_traits<Q>::from_numerical_value(numerical_value_).value;
|
||||
}
|
||||
|
||||
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>>
|
||||
requires detail::QuantityConvertibleTo<
|
||||
quantity, quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>>
|
||||
[[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(numerical_value_)),
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<Rep, typename Q::rep>) constexpr
|
||||
operator Q_() && noexcept(noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_)) &&
|
||||
std::is_nothrow_move_constructible_v<rep>)
|
||||
{
|
||||
return quantity_like_traits<Q>::from_numerical_value(std::move(numerical_value_)).value;
|
||||
}
|
||||
|
||||
// member unary operators
|
||||
[[nodiscard]] constexpr Quantity auto operator+() const
|
||||
requires requires(rep v) {
|
||||
@ -365,7 +392,9 @@ private:
|
||||
|
||||
// CTAD
|
||||
template<QuantityLike Q>
|
||||
explicit quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
||||
explicit(
|
||||
is_specialization_of<decltype(quantity_like_traits<Q>::to_numerical_value(std::declval<Q>())), convert_explicitly>)
|
||||
quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
// binary operators on quantities
|
||||
template<auto R1, typename Rep1, auto R2, typename Rep2>
|
||||
|
@ -128,8 +128,13 @@ public:
|
||||
std::convertible_to<
|
||||
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>,
|
||||
quantity_type>
|
||||
constexpr explicit quantity_point(const QP& qp) :
|
||||
quantity_from_origin_(quantity_point_like_traits<QP>::quantity_from_origin(qp))
|
||||
constexpr explicit(
|
||||
is_specialization_of<decltype(quantity_point_like_traits<QP>::to_quantity(std::declval<QP>())),
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<
|
||||
quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>, quantity_type>)
|
||||
quantity_point(const QP& qp) :
|
||||
quantity_from_origin_(quantity_point_like_traits<QP>::to_quantity(qp).value)
|
||||
{
|
||||
}
|
||||
|
||||
@ -137,7 +142,8 @@ public:
|
||||
quantity_point& operator=(quantity_point&&) = default;
|
||||
|
||||
template<PointOriginFor<quantity_spec> NewPO>
|
||||
[[nodiscard]] constexpr QuantityPointOf<NewPO{}> auto point_for(NewPO new_origin) const
|
||||
[[nodiscard]] constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(QuantityPointOf<NewPO{}>) auto point_for(
|
||||
NewPO new_origin) const
|
||||
{
|
||||
if constexpr (is_same_v<NewPO, std::remove_const_t<decltype(point_origin)>>)
|
||||
return *this;
|
||||
@ -168,6 +174,7 @@ public:
|
||||
return *this - PO2{};
|
||||
}
|
||||
|
||||
// unit conversions
|
||||
template<UnitCompatibleWith<unit, quantity_spec> U>
|
||||
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, U{}), Rep>>
|
||||
[[nodiscard]] constexpr QuantityPoint auto in(U) const
|
||||
@ -182,6 +189,39 @@ public:
|
||||
return make_quantity_point<PO>(quantity_ref_from(PO).force_in(U{}));
|
||||
}
|
||||
|
||||
// conversion operators
|
||||
template<typename QP_, QuantityPointLike QP = std::remove_cvref_t<QP_>>
|
||||
requires std::same_as<std::remove_const_t<decltype(point_origin)>,
|
||||
std::remove_const_t<decltype(quantity_point_like_traits<QP>::point_origin)>> &&
|
||||
std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>
|
||||
[[nodiscard]] explicit(
|
||||
is_specialization_of<decltype(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_)),
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
||||
operator QP_() const& noexcept(noexcept(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_)) &&
|
||||
std::is_nothrow_copy_constructible_v<rep>)
|
||||
{
|
||||
return quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_).value;
|
||||
}
|
||||
|
||||
template<typename QP_, QuantityPointLike QP = std::remove_cvref_t<QP_>>
|
||||
requires std::same_as<std::remove_const_t<decltype(point_origin)>,
|
||||
std::remove_const_t<decltype(quantity_point_like_traits<QP>::point_origin)>> &&
|
||||
std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>
|
||||
[[nodiscard]] explicit(
|
||||
is_specialization_of<decltype(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_)),
|
||||
convert_explicitly> ||
|
||||
!std::convertible_to<quantity_type, quantity<quantity_point_like_traits<QP>::reference,
|
||||
typename quantity_point_like_traits<QP>::rep>>) constexpr
|
||||
operator QP_() && noexcept(noexcept(quantity_point_like_traits<QP>::from_quantity(quantity_from_origin_)) &&
|
||||
std::is_nothrow_move_constructible_v<rep>)
|
||||
{
|
||||
return quantity_point_like_traits<QP>::from_quantity(std::move(quantity_from_origin_)).value;
|
||||
}
|
||||
|
||||
// member unary operators
|
||||
template<typename QP>
|
||||
friend constexpr decltype(auto) operator++(QP&& qp)
|
||||
@ -249,7 +289,9 @@ private:
|
||||
|
||||
// CTAD
|
||||
template<QuantityPointLike QP>
|
||||
explicit quantity_point(QP)
|
||||
explicit(
|
||||
is_specialization_of<decltype(quantity_point_like_traits<QP>::to_quantity(std::declval<QP>())), convert_explicitly>)
|
||||
quantity_point(QP)
|
||||
-> quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
|
||||
typename quantity_point_like_traits<QP>::rep>;
|
||||
|
||||
|
@ -41,12 +41,12 @@ namespace detail {
|
||||
|
||||
template<QuantitySpec QS, Unit U>
|
||||
requires(!AssociatedUnit<U>) || UnitOf<U, QS{}>
|
||||
[[nodiscard]] consteval Reference auto make_reference(QS qs, U u)
|
||||
[[nodiscard]] consteval Reference auto make_reference(QS, U u)
|
||||
{
|
||||
if constexpr (detail::QuantityKindSpec<QS>)
|
||||
return u;
|
||||
else
|
||||
return reference<qs, u>{};
|
||||
return reference<QS{}, U{}>{};
|
||||
}
|
||||
|
||||
// TODO revise the note in the below comment
|
||||
@ -494,9 +494,10 @@ template<QuantitySpec auto... From, QuantitySpec Q>
|
||||
|
||||
// Operators
|
||||
|
||||
[[nodiscard]] consteval QuantitySpec auto operator*(QuantitySpec auto lhs, QuantitySpec auto rhs)
|
||||
template<QuantitySpec Lhs, QuantitySpec Rhs>
|
||||
[[nodiscard]] consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs)
|
||||
{
|
||||
return detail::clone_kind_of<lhs, rhs>(
|
||||
return detail::clone_kind_of<Lhs{}, Rhs{}>(
|
||||
detail::expr_multiply<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
|
||||
remove_kind(lhs), remove_kind(rhs)));
|
||||
}
|
||||
@ -504,7 +505,7 @@ template<QuantitySpec auto... From, QuantitySpec Q>
|
||||
template<QuantitySpec Lhs, QuantitySpec Rhs>
|
||||
[[nodiscard]] consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs)
|
||||
{
|
||||
return detail::clone_kind_of<lhs, rhs>(
|
||||
return detail::clone_kind_of<Lhs{}, Rhs{}>(
|
||||
detail::expr_divide<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
|
||||
remove_kind(lhs), remove_kind(rhs)));
|
||||
}
|
||||
@ -548,7 +549,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
|
||||
// `2 * one * (2 * one)` should compare to `4 * one`
|
||||
// `2 * rad * (2 * rad)` should compare to `4 * rad^2`
|
||||
// all are dimensionless quantities :-(
|
||||
if constexpr (Num == 0 || q == dimensionless)
|
||||
if constexpr (Num == 0 || Q{} == dimensionless)
|
||||
return dimensionless;
|
||||
else if constexpr (ratio{Num, Den} == 1)
|
||||
return q;
|
||||
@ -773,7 +774,7 @@ template<int Complexity, QuantitySpec Q>
|
||||
template<int Complexity, IntermediateDerivedQuantitySpec Q>
|
||||
[[nodiscard]] consteval auto explode(Q q)
|
||||
{
|
||||
constexpr auto c = get_complexity(q);
|
||||
constexpr auto c = get_complexity(Q{});
|
||||
if constexpr (c > Complexity)
|
||||
return explode<Complexity>(q, type_list_sort<typename Q::_num_, type_list_of_ingredients_less>{},
|
||||
type_list_sort<typename Q::_den_, type_list_of_ingredients_less>{});
|
||||
@ -784,9 +785,9 @@ template<int Complexity, IntermediateDerivedQuantitySpec Q>
|
||||
template<int Complexity, NamedQuantitySpec Q>
|
||||
[[nodiscard]] consteval auto explode(Q q)
|
||||
{
|
||||
constexpr auto c = get_complexity(q);
|
||||
constexpr auto c = get_complexity(Q{});
|
||||
if constexpr (c > Complexity && requires { Q::_equation_; }) {
|
||||
constexpr auto res = explode_to_equation(q);
|
||||
constexpr auto res = explode_to_equation(Q{});
|
||||
return explode<Complexity>(res.equation).common_convertibility_with(res);
|
||||
} else
|
||||
return explode_result{q};
|
||||
@ -879,10 +880,10 @@ extract_results(bool, From = {}, To = {}, prepend_rest = {}, Elem = {}) -> extra
|
||||
#endif
|
||||
|
||||
template<typename From, typename To>
|
||||
[[nodiscard]] consteval auto extract_convertible_quantities(From from, To to)
|
||||
[[nodiscard]] consteval auto extract_convertible_quantities(From, To)
|
||||
{
|
||||
constexpr auto qfrom = map_power(from);
|
||||
constexpr auto qto = map_power(to);
|
||||
constexpr auto qfrom = map_power(From{});
|
||||
constexpr auto qto = map_power(To{});
|
||||
if constexpr (qfrom.dimension == qto.dimension) {
|
||||
if constexpr (is_specialization_of_power<From> && is_specialization_of_power<To>) {
|
||||
constexpr auto cr = common_ratio(From::exponent, To::exponent);
|
||||
@ -899,8 +900,8 @@ template<typename From, typename To>
|
||||
else
|
||||
return std::tuple{Q{}, ratio{1}};
|
||||
};
|
||||
constexpr auto from_norm = normalize(from);
|
||||
constexpr auto to_norm = normalize(to);
|
||||
constexpr auto from_norm = normalize(From{});
|
||||
constexpr auto to_norm = normalize(To{});
|
||||
constexpr auto from_factor = std::get<0>(from_norm);
|
||||
constexpr auto from_exp = std::get<1>(from_norm);
|
||||
constexpr auto to_factor = std::get<0>(to_norm);
|
||||
@ -1329,11 +1330,11 @@ template<QuantitySpec From, QuantitySpec To>
|
||||
|
||||
if constexpr (From::dimension != To::dimension)
|
||||
return no;
|
||||
else if constexpr (from == to)
|
||||
else if constexpr (From{} == To{})
|
||||
return yes;
|
||||
else if constexpr (QuantityKindSpec<From> || QuantityKindSpec<To>) {
|
||||
constexpr auto from_kind = get_kind(from);
|
||||
constexpr auto to_kind = get_kind(to);
|
||||
constexpr auto from_kind = get_kind(From{});
|
||||
constexpr auto to_kind = get_kind(To{});
|
||||
constexpr auto exploded_kind_result = [](specs_convertible_result res) {
|
||||
using enum specs_convertible_result;
|
||||
return res == no ? no : yes;
|
||||
@ -1348,21 +1349,21 @@ template<QuantitySpec From, QuantitySpec To>
|
||||
else
|
||||
return exploded_kind_result(
|
||||
convertible_impl(from_kind, get_kind(explode<get_complexity(from_kind)>(to_kind).quantity)));
|
||||
} else if constexpr (NestedQuantityKindSpecOf<get_kind(to), from> && get_kind(to) == to)
|
||||
} else if constexpr (NestedQuantityKindSpecOf<get_kind(To{}), from> && get_kind(To{}) == To{})
|
||||
return yes;
|
||||
else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) {
|
||||
if constexpr (have_common_base(from, to)) {
|
||||
if constexpr (have_common_base(From{}, To{})) {
|
||||
if (std::derived_from<From, To>)
|
||||
return yes;
|
||||
else
|
||||
return std::derived_from<To, From> ? explicit_conversion : (get_kind(from) == get_kind(to) ? cast : no);
|
||||
} else if constexpr (get_kind(from) != get_kind(to))
|
||||
} else if constexpr (get_kind(From{}) != get_kind(To{}))
|
||||
return no;
|
||||
else if constexpr (get_complexity(from) != get_complexity(to)) {
|
||||
if constexpr (get_complexity(from) > get_complexity(to))
|
||||
else if constexpr (get_complexity(From{}) != get_complexity(To{})) {
|
||||
if constexpr (get_complexity(From{}) > get_complexity(To{}))
|
||||
return convertible_impl(explode<get_complexity(to)>(from).quantity, to);
|
||||
else {
|
||||
constexpr auto res = explode<get_complexity(from)>(to);
|
||||
auto res = explode<get_complexity(from)>(to);
|
||||
return min(res.result, convertible_impl(from, res.quantity));
|
||||
}
|
||||
}
|
||||
@ -1373,7 +1374,7 @@ template<QuantitySpec From, QuantitySpec To>
|
||||
if constexpr (NamedQuantitySpec<std::remove_const_t<decltype(res.quantity)>>)
|
||||
return convertible_impl(res.quantity, to);
|
||||
else if constexpr (requires { to._equation_; }) {
|
||||
constexpr auto eq = explode_to_equation(to);
|
||||
auto eq = explode_to_equation(to);
|
||||
return min(eq.result, convertible_impl(res.quantity, eq.equation));
|
||||
} else
|
||||
return are_ingredients_convertible(from, to);
|
||||
@ -1443,16 +1444,16 @@ template<QuantitySpec Q>
|
||||
template<QuantitySpec Q>
|
||||
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q)
|
||||
{
|
||||
auto defined_as_kind = [](auto qq) {
|
||||
auto defined_as_kind = []<typename QQ>(QQ qq) {
|
||||
if constexpr (requires { detail::defined_as_kind(qq); })
|
||||
return detail::defined_as_kind(qq);
|
||||
return detail::defined_as_kind(QQ{});
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
if constexpr (detail::QuantityKindSpec<Q>) {
|
||||
return remove_kind(q);
|
||||
} else if constexpr (defined_as_kind(q)) {
|
||||
} else if constexpr (defined_as_kind(Q{})) {
|
||||
return q;
|
||||
} else if constexpr (requires { Q::_parent_; }) {
|
||||
return get_kind(Q::_parent_);
|
||||
@ -1475,25 +1476,25 @@ template<QuantitySpec Q1, QuantitySpec Q2>
|
||||
using QQ2 = std::remove_const_t<decltype(remove_kind(q2))>;
|
||||
if constexpr (is_same_v<Q1, Q2>)
|
||||
return q1;
|
||||
else if constexpr (detail::NestedQuantityKindSpecOf<q1, q2>)
|
||||
else if constexpr (detail::NestedQuantityKindSpecOf<Q1{}, Q2{}>)
|
||||
return remove_kind(q1);
|
||||
else if constexpr (detail::NestedQuantityKindSpecOf<q2, q1>)
|
||||
else if constexpr (detail::NestedQuantityKindSpecOf<Q2{}, Q1{}>)
|
||||
return remove_kind(q2);
|
||||
else if constexpr ((detail::QuantityKindSpec<Q1> && !detail::QuantityKindSpec<Q2>) ||
|
||||
(detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> &&
|
||||
implicitly_convertible(q1, q2)))
|
||||
implicitly_convertible(Q1{}, Q2{})))
|
||||
return q2;
|
||||
else if constexpr ((!detail::QuantityKindSpec<Q1> && detail::QuantityKindSpec<Q2>) ||
|
||||
(detail::NamedQuantitySpec<QQ1> && detail::IntermediateDerivedQuantitySpec<QQ2> &&
|
||||
implicitly_convertible(q2, q1)))
|
||||
implicitly_convertible(Q2{}, Q1{})))
|
||||
return q1;
|
||||
else if constexpr (detail::have_common_base(q1, q2))
|
||||
else if constexpr (detail::have_common_base(Q1{}, Q2{}))
|
||||
return detail::get_common_base(q1, q2);
|
||||
else if constexpr (implicitly_convertible(q1, q2))
|
||||
else if constexpr (implicitly_convertible(Q1{}, Q2{}))
|
||||
return q2;
|
||||
else if constexpr (implicitly_convertible(q2, q1))
|
||||
else if constexpr (implicitly_convertible(Q2{}, Q1{}))
|
||||
return q1;
|
||||
else if constexpr (implicitly_convertible(get_kind(q1), get_kind(q2)))
|
||||
else if constexpr (implicitly_convertible(get_kind(Q1{}), get_kind(Q2{})))
|
||||
return get_kind(q2);
|
||||
else
|
||||
return get_kind(q1);
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/external/hacks.h>
|
||||
#include <mp-units/bits/get_associated_quantity.h>
|
||||
#include <mp-units/bits/quantity_concepts.h>
|
||||
#include <mp-units/bits/reference_concepts.h>
|
||||
@ -73,13 +74,21 @@ struct reference {
|
||||
}
|
||||
|
||||
template<AssociatedUnit U2>
|
||||
#if MP_UNITS_COMP_MSVC
|
||||
[[nodiscard]] friend consteval decltype(reference<Q * get_quantity_spec(U2{}), U * U2{}>{}) operator*(reference, U2)
|
||||
#else
|
||||
[[nodiscard]] friend consteval reference<Q * get_quantity_spec(U2{}), U * U2{}> operator*(reference, U2)
|
||||
#endif
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<AssociatedUnit U1>
|
||||
#if MP_UNITS_COMP_MSVC
|
||||
[[nodiscard]] friend consteval decltype(reference<get_quantity_spec(U1{}) * Q, U1{} * U>{}) operator*(U1, reference)
|
||||
#else
|
||||
[[nodiscard]] friend consteval reference<get_quantity_spec(U1{}) * Q, U1{} * U> operator*(U1, reference)
|
||||
#endif
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@ -91,13 +100,21 @@ struct reference {
|
||||
}
|
||||
|
||||
template<AssociatedUnit U2>
|
||||
#if MP_UNITS_COMP_MSVC
|
||||
[[nodiscard]] friend consteval decltype(reference<Q / get_quantity_spec(U2{}), U / U2{}>{}) operator/(reference, U2)
|
||||
#else
|
||||
[[nodiscard]] friend consteval reference<Q / get_quantity_spec(U2{}), U / U2{}> operator/(reference, U2)
|
||||
#endif
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<AssociatedUnit U1>
|
||||
#if MP_UNITS_COMP_MSVC
|
||||
[[nodiscard]] friend consteval decltype(reference<get_quantity_spec(U1{}) / Q, U1{} / U>{}) operator/(U1, reference)
|
||||
#else
|
||||
[[nodiscard]] friend consteval reference<get_quantity_spec(U1{}) / Q, U1{} / U> operator/(U1, reference)
|
||||
#endif
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/external/hacks.h>
|
||||
#include <mp-units/quantity_spec.h>
|
||||
#include <mp-units/reference.h>
|
||||
#include <mp-units/unit.h>
|
||||
@ -63,7 +64,11 @@ struct system_reference {
|
||||
|
||||
template<Unit U>
|
||||
requires(convertible(coherent_unit, U{}))
|
||||
#if MP_UNITS_COMP_MSVC
|
||||
[[nodiscard]] constexpr decltype(reference<quantity_spec, U{}>{}) operator[](U) const
|
||||
#else
|
||||
[[nodiscard]] constexpr reference<quantity_spec, U{}> operator[](U) const
|
||||
#endif
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
@ -354,9 +354,9 @@ template<typename T, typename F, int Num, int... Den>
|
||||
template<typename... Us>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(const type_list<Us...>&)
|
||||
{
|
||||
auto mag = (mp_units::mag<1> * ... * get_canonical_unit_impl(Us{}, Us{}).mag);
|
||||
auto m = (mp_units::mag<1> * ... * get_canonical_unit_impl(Us{}, Us{}).mag);
|
||||
auto u = (one * ... * get_canonical_unit_impl(Us{}, Us{}).reference_unit);
|
||||
return canonical_unit{mag, u};
|
||||
return canonical_unit{m, u};
|
||||
}
|
||||
|
||||
template<Unit T, typename... Expr>
|
||||
@ -402,12 +402,12 @@ using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
|
||||
* Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned.
|
||||
*/
|
||||
template<Magnitude M, Unit U>
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M mag, const U u)
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M, const U u)
|
||||
{
|
||||
if constexpr (mag == mp_units::mag<1>)
|
||||
if constexpr (std::is_same_v<M, std::remove_cvref_t<decltype(mp_units::mag<1>)>>)
|
||||
return u;
|
||||
else
|
||||
return scaled_unit<mag, U>{};
|
||||
return scaled_unit<M{}, U>{};
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval Unit auto operator*(Unit auto, Magnitude auto) = delete;
|
||||
|
@ -64,7 +64,18 @@ template<typename Rep, typename Period>
|
||||
struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
|
||||
static constexpr auto reference = detail::time_unit_from_chrono_period<Period>();
|
||||
using rep = Rep;
|
||||
[[nodiscard]] static constexpr rep value(const std::chrono::duration<Rep, Period>& q) { return q.count(); }
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<rep> to_numerical_value(
|
||||
const std::chrono::duration<Rep, Period>& q) noexcept(std::is_nothrow_copy_constructible_v<rep>)
|
||||
{
|
||||
return q.count();
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<std::chrono::duration<Rep, Period>> from_numerical_value(
|
||||
const rep& v) noexcept(std::is_nothrow_copy_constructible_v<rep>)
|
||||
{
|
||||
return std::chrono::duration<Rep, Period>(v);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
@ -77,14 +88,22 @@ inline constexpr chrono_point_origin_<C> chrono_point_origin;
|
||||
|
||||
template<typename C, typename Rep, typename Period>
|
||||
struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> {
|
||||
using T = std::chrono::time_point<C, std::chrono::duration<Rep, Period>>;
|
||||
static constexpr auto reference = detail::time_unit_from_chrono_period<Period>();
|
||||
static constexpr auto point_origin = chrono_point_origin<C>;
|
||||
using rep = Rep;
|
||||
[[nodiscard]] static constexpr quantity<reference, rep> quantity_from_origin(
|
||||
const std::chrono::time_point<C, std::chrono::duration<Rep, Period>>& qp)
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<quantity<reference, rep>> to_quantity(const T& qp) noexcept(
|
||||
std::is_nothrow_copy_constructible_v<rep>)
|
||||
{
|
||||
return quantity{qp.time_since_epoch()};
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr convert_implicitly<T> from_quantity(const quantity<reference, rep>& q) noexcept(
|
||||
std::is_nothrow_copy_constructible_v<rep>)
|
||||
{
|
||||
return T(q);
|
||||
}
|
||||
};
|
||||
|
||||
template<QuantityOf<isq::time> Q>
|
||||
@ -92,7 +111,7 @@ template<QuantityOf<isq::time> Q>
|
||||
{
|
||||
constexpr auto canonical = detail::get_canonical_unit(Q::unit);
|
||||
constexpr ratio r = as_ratio(canonical.mag);
|
||||
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q.numerical_value_ref_in(Q::unit)};
|
||||
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q};
|
||||
}
|
||||
|
||||
template<QuantityPointOf<isq::time> QP>
|
||||
|
@ -52,40 +52,40 @@ static_assert(!QuantityPoint<sys_seconds>);
|
||||
// construction - same rep type
|
||||
static_assert(
|
||||
std::constructible_from<quantity<isq::time[si::second], std::chrono::seconds::rep>, std::chrono::seconds>);
|
||||
static_assert(!std::convertible_to<std::chrono::seconds, quantity<isq::time[si::second], std::chrono::seconds::rep>>);
|
||||
static_assert(std::convertible_to<std::chrono::seconds, quantity<isq::time[si::second], std::chrono::seconds::rep>>);
|
||||
static_assert(std::constructible_from<quantity<isq::time[si::hour], std::chrono::hours::rep>, std::chrono::hours>);
|
||||
static_assert(!std::convertible_to<std::chrono::hours, quantity<isq::time[si::hour], std::chrono::hours::rep>>);
|
||||
static_assert(std::convertible_to<std::chrono::hours, quantity<isq::time[si::hour], std::chrono::hours::rep>>);
|
||||
static_assert(std::constructible_from<quantity<isq::time[si::second], std::chrono::hours::rep>, std::chrono::hours>);
|
||||
static_assert(!std::convertible_to<std::chrono::hours, quantity<isq::time[si::second], std::chrono::hours::rep>>);
|
||||
static_assert(std::convertible_to<std::chrono::hours, quantity<isq::time[si::second], std::chrono::hours::rep>>);
|
||||
static_assert(!std::constructible_from<quantity<isq::time[si::hour], std::chrono::seconds::rep>, std::chrono::seconds>);
|
||||
static_assert(!std::convertible_to<std::chrono::seconds, quantity<isq::time[si::hour], std::chrono::seconds::rep>>);
|
||||
static_assert(
|
||||
std::constructible_from<time_point<si::second, std::chrono::system_clock, sys_seconds::rep>, sys_seconds>);
|
||||
static_assert(
|
||||
!std::constructible_from<time_point<si::second, std::chrono::steady_clock, sys_seconds::rep>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<si::second, std::chrono::system_clock, sys_seconds::rep>>);
|
||||
static_assert(std::convertible_to<sys_seconds, time_point<si::second, std::chrono::system_clock, sys_seconds::rep>>);
|
||||
static_assert(std::constructible_from<time_point<si::day, std::chrono::system_clock, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::constructible_from<time_point<si::day, std::chrono::steady_clock, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<si::day, std::chrono::system_clock, sys_days::rep>>);
|
||||
static_assert(std::convertible_to<sys_days, time_point<si::day, std::chrono::system_clock, sys_days::rep>>);
|
||||
static_assert(std::constructible_from<time_point<si::second, std::chrono::system_clock, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::constructible_from<time_point<si::second, std::chrono::steady_clock, sys_days::rep>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<si::second, std::chrono::system_clock, sys_days::rep>>);
|
||||
static_assert(std::convertible_to<sys_days, time_point<si::second, std::chrono::system_clock, sys_days::rep>>);
|
||||
static_assert(!std::constructible_from<time_point<si::day, std::chrono::system_clock, sys_seconds::rep>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<si::day, std::chrono::system_clock, sys_seconds::rep>>);
|
||||
|
||||
// construction - different rep type (integral to a floating-point)
|
||||
static_assert(std::constructible_from<quantity<isq::time[si::second]>, std::chrono::seconds>);
|
||||
static_assert(!std::convertible_to<std::chrono::seconds, quantity<isq::time[si::second]>>);
|
||||
static_assert(std::convertible_to<std::chrono::seconds, quantity<isq::time[si::second]>>);
|
||||
static_assert(std::constructible_from<quantity<isq::time[si::second]>, std::chrono::hours>);
|
||||
static_assert(!std::convertible_to<std::chrono::hours, quantity<isq::time[si::second]>>);
|
||||
static_assert(std::convertible_to<std::chrono::hours, quantity<isq::time[si::second]>>);
|
||||
static_assert(std::constructible_from<quantity<isq::time[si::hour]>, std::chrono::seconds>);
|
||||
static_assert(!std::convertible_to<std::chrono::seconds, quantity<isq::time[si::hour]>>);
|
||||
static_assert(std::convertible_to<std::chrono::seconds, quantity<isq::time[si::hour]>>);
|
||||
static_assert(std::constructible_from<time_point<si::second, std::chrono::system_clock>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<si::second, std::chrono::system_clock>>);
|
||||
static_assert(std::convertible_to<sys_seconds, time_point<si::second, std::chrono::system_clock>>);
|
||||
static_assert(std::constructible_from<time_point<si::second, std::chrono::system_clock>, sys_days>);
|
||||
static_assert(!std::convertible_to<sys_days, time_point<si::second, std::chrono::system_clock>>);
|
||||
static_assert(std::convertible_to<sys_days, time_point<si::second, std::chrono::system_clock>>);
|
||||
static_assert(std::constructible_from<time_point<si::day, std::chrono::system_clock>, sys_seconds>);
|
||||
static_assert(!std::convertible_to<sys_seconds, time_point<si::day, std::chrono::system_clock>>);
|
||||
static_assert(std::convertible_to<sys_seconds, time_point<si::day, std::chrono::system_clock>>);
|
||||
|
||||
static_assert(quantity<si::second>{1s} == 1 * s);
|
||||
static_assert(quantity<isq::time[si::second]>{1s} == 1 * s);
|
||||
|
@ -525,7 +525,7 @@ static_assert(!std::convertible_to<quantity_point<isq::height[m], ground_level>,
|
||||
static_assert(
|
||||
std::constructible_from<quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>, sys_seconds>);
|
||||
static_assert(
|
||||
!std::convertible_to<sys_seconds, quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>>);
|
||||
std::convertible_to<sys_seconds, quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>>);
|
||||
|
||||
// incompatible origin
|
||||
static_assert(
|
||||
|
Reference in New Issue
Block a user