refactor: 💥 make_xxx factory functions replaced with two-parameter constructors

Resolves #521
This commit is contained in:
Mateusz Pusz
2023-11-28 11:52:37 +01:00
parent 80129b32d7
commit fa596fffc6
12 changed files with 143 additions and 175 deletions

View File

@ -50,15 +50,15 @@ quantity q = 42 * m;
namespace.
In case someone doesn't like the multiply syntax or there is an ambiguity between `operator*`
provided by this and other libraries, a quantity can also be created with a dedicated factory
function:
provided by this and other libraries, a quantity can also be created with a two-parameter
constructor:
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units;
quantity q = make_quantity<si::metre>(42);
quantity q{42, si::metre};
```

View File

@ -191,10 +191,10 @@ Quantity auto q = la_vector{1, 2, 3} * isq::velocity[m / s];
In case there is an ambiguity of `operator*` between **mp-units** and a linear algebra library, we can
either:
- use `make_quantity` factory function
- use two-parameter constructor
```cpp
Quantity auto q = make_quantity<isq::velocity[m / s]>(la_vector{1, 2, 3});
Quantity auto q = quantity{la_vector{1, 2, 3}, isq::velocity[m / s]};
```
- provide a dedicated overload of `operator*` that will resolve the ambiguity and wrap the above
@ -203,7 +203,7 @@ either:
template<Reference R>
Quantity auto operator*(la_vector rep, R)
{
return make_quantity<R{}>(rep);
return quantity{rep, R{}};
}
```

View File

@ -102,11 +102,11 @@ quantity_point qp3 = mean_sea_level - 42 * m;
Similarly to [creation of a quantity](../../getting_started/quick_start.md#creating-a-quantity),
if someone does not like the operator-based syntax to create a `quantity_point`, the same results
can be achieved with `make_quantity_point` factory function:
can be achieved with two-parameter constructor:
```cpp
quantity_point qp4 = make_quantity_point<mean_sea_level>(42 * m);
quantity_point qp5 = make_quantity_point<mean_sea_level>(-42 * m);
quantity_point qp4{42 * m, mean_sea_level};
quantity_point qp5{-42 * m, mean_sea_level};
```
The provided `quantity` representing an offset from the origin is stored inside the `quantity_point`

View File

@ -51,9 +51,9 @@ template<QuantitySpec auto ToQS, typename Q>
{
if constexpr (detail::QuantityKindSpec<std::remove_const_t<decltype(ToQS)>> &&
AssociatedUnit<std::remove_const_t<decltype(Q::unit)>>)
return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, Q::unit};
else
return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, reference<ToQS, Q::unit>{}};
}
} // namespace mp_units

View File

@ -32,13 +32,6 @@ namespace mp_units {
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep>
class quantity;
#if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17
template<auto R, typename Rep>
#else
template<Reference auto R, typename Rep>
#endif
[[nodiscard]] constexpr quantity<R, std::remove_cvref_t<Rep>> make_quantity(Rep&& v);
namespace detail {
template<auto R, typename Rep>

View File

@ -109,14 +109,6 @@ template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R).character> Rep>
class quantity_point;
#if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17
template<auto PO, typename Q>
#else
template<PointOrigin auto PO, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO.quantity_spec>
#endif
[[nodiscard]] constexpr quantity_point<Q::reference, PO, typename Q::rep> make_quantity_point(Q&& q);
namespace detail {
template<auto R, auto PO, typename Rep>

View File

@ -57,17 +57,16 @@ template<Quantity To, typename From>
std::constructible_from<typename To::rep, typename std::remove_reference_t<From>::rep>) ||
(std::remove_reference_t<From>::unit != To::unit)) // && scalable_with_<typename To::rep>))
// TODO how to constrain the second part here?
[[nodiscard]] constexpr Quantity auto sudo_cast(From&& q)
[[nodiscard]] constexpr To sudo_cast(From&& q)
{
constexpr auto q_unit = std::remove_reference_t<From>::unit;
if constexpr (q_unit == To::unit) {
// no scaling of the number needed
return make_quantity<To::reference>(static_cast<MP_UNITS_TYPENAME To::rep>(
std::forward<From>(q)
.numerical_value_is_an_implementation_detail_)); // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler
// warnings on conversions
return {static_cast<MP_UNITS_TYPENAME To::rep>(std::forward<From>(q).numerical_value_is_an_implementation_detail_),
To::reference}; // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler
// warnings on conversions
} else {
// scale the number
constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / get_canonical_unit(To::unit).mag;
@ -79,10 +78,10 @@ template<Quantity To, typename From>
using multiplier_type =
conditional<treat_as_floating_point<c_rep_type>, std::common_type_t<c_mag_type, long double>, c_mag_type>;
constexpr auto val = [](Magnitude auto m) { return get_value<multiplier_type>(m); };
return static_cast<MP_UNITS_TYPENAME To::rep>(
static_cast<c_rep_type>(std::forward<From>(q).numerical_value_is_an_implementation_detail_) * val(num) /
val(den) * val(irr)) *
To::reference;
return {static_cast<MP_UNITS_TYPENAME To::rep>(
static_cast<c_rep_type>(std::forward<From>(q).numerical_value_is_an_implementation_detail_) * val(num) /
val(den) * val(irr)),
To::reference};
}
}

View File

@ -94,7 +94,7 @@ using common_quantity_for = quantity<common_reference(Q1::reference, Q2::referen
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep = double>
class quantity {
public:
Rep numerical_value_is_an_implementation_detail_; // needs to be public for a structural type
Rep numerical_value_is_an_implementation_detail_; ///< needs to be public for a structural type
// member types and values
static constexpr Reference auto reference = R;
@ -107,25 +107,25 @@ public:
[[nodiscard]] static constexpr quantity zero() noexcept
requires requires { quantity_values<rep>::zero(); }
{
return quantity(quantity_values<rep>::zero());
return {quantity_values<rep>::zero(), R};
}
[[nodiscard]] static constexpr quantity one() noexcept
requires requires { quantity_values<rep>::one(); }
{
return quantity(quantity_values<rep>::one());
return {quantity_values<rep>::one(), R};
}
[[nodiscard]] static constexpr quantity min() noexcept
requires requires { quantity_values<rep>::min(); }
{
return quantity(quantity_values<rep>::min());
return {quantity_values<rep>::min(), R};
}
[[nodiscard]] static constexpr quantity max() noexcept
requires requires { quantity_values<rep>::max(); }
{
return quantity(quantity_values<rep>::max());
return {quantity_values<rep>::max(), R};
}
// construction, assignment, destruction
@ -133,6 +133,19 @@ public:
quantity(const quantity&) = default;
quantity(quantity&&) = default;
template<typename Value>
requires std::same_as<std::remove_cvref_t<Value>, Rep>
constexpr quantity(Value&& v, std::remove_const_t<decltype(R)>) :
numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
{
}
template<typename Value, Reference R2>
requires detail::QuantityConvertibleTo<quantity<R2{}, std::remove_cvref_t<Value>>, quantity>
constexpr quantity(Value&& v, R2) : quantity(quantity<R2{}, std::remove_cvref_t<Value>>{std::forward<Value>(v), R2{}})
{
}
template<detail::QuantityConvertibleTo<quantity> Q>
constexpr explicit(!std::convertible_to<typename Q::rep, Rep>) quantity(const Q& q) :
numerical_value_is_an_implementation_detail_(
@ -146,7 +159,8 @@ public:
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(
::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q).value, quantity_like_traits<Q>::reference})
{
}
@ -238,7 +252,7 @@ public:
} -> std::common_with<rep>;
}
{
return make_quantity<reference>(+numerical_value_is_an_implementation_detail_);
return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, reference};
}
[[nodiscard]] constexpr Quantity auto operator-() const
@ -248,7 +262,7 @@ public:
} -> std::common_with<rep>;
}
{
return make_quantity<reference>(-numerical_value_is_an_implementation_detail_);
return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference};
}
template<typename Q>
@ -270,7 +284,7 @@ public:
} -> std::common_with<rep>;
}
{
return make_quantity<reference>(numerical_value_is_an_implementation_detail_++);
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference};
}
template<typename Q>
@ -292,7 +306,7 @@ public:
} -> std::common_with<rep>;
}
{
return make_quantity<reference>(numerical_value_is_an_implementation_detail_--);
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, reference};
}
// compound assignment operators
@ -388,23 +402,13 @@ public:
lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs);
}
private:
#if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17
template<auto R2, typename Rep2>
#else
template<Reference auto R2, typename Rep2>
#endif
friend constexpr quantity<R2, std::remove_cvref_t<Rep2>> make_quantity(Rep2&&);
template<typename Value>
requires std::constructible_from<rep, Value&&>
constexpr explicit quantity(Value&& v) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
{
}
};
// CTAD
template<typename Value, Reference R>
requires RepresentationOf<Value, get_quantity_spec(R{}).character>
quantity(Value v, R) -> quantity<R{}, Value>;
template<QuantityLike Q>
explicit(
is_specialization_of<decltype(quantity_like_traits<Q>::to_numerical_value(std::declval<Q>())), convert_explicitly>)
@ -418,8 +422,8 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
using ret = detail::common_quantity_for<std::plus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return make_quantity<ret::reference>(ret_lhs.numerical_value_ref_in(ret::unit) +
ret_rhs.numerical_value_ref_in(ret::unit));
return quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -429,8 +433,8 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
using ret = detail::common_quantity_for<std::minus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return make_quantity<ret::reference>(ret_lhs.numerical_value_ref_in(ret::unit) -
ret_rhs.numerical_value_ref_in(ret::unit));
return quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -442,15 +446,15 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
using ret = detail::common_quantity_for<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return make_quantity<ret::reference>(ret_lhs.numerical_value_ref_in(ret::unit) %
ret_rhs.numerical_value_ref_in(ret::unit));
return quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
requires detail::InvocableQuantities<std::multiplies<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator*(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
return make_quantity<R1 * R2>(lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)));
return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), R1 * R2};
}
template<auto R, typename Rep, typename Value>
@ -458,7 +462,7 @@ template<auto R, typename Rep, typename Value>
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, Rep, const Value&>
[[nodiscard]] constexpr Quantity auto operator*(const quantity<R, Rep>& q, const Value& v)
{
return make_quantity<R>(q.numerical_value_ref_in(get_unit(R)) * v);
return quantity{q.numerical_value_ref_in(get_unit(R)) * v, R};
}
template<typename Value, auto R, typename Rep>
@ -466,7 +470,7 @@ template<typename Value, auto R, typename Rep>
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, const Value&, Rep>
[[nodiscard]] constexpr Quantity auto operator*(const Value& v, const quantity<R, Rep>& q)
{
return make_quantity<R>(v * q.numerical_value_ref_in(get_unit(R)));
return quantity{v * q.numerical_value_ref_in(get_unit(R)), R};
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -474,7 +478,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
gsl_ExpectsAudit(rhs != rhs.zero());
return make_quantity<R1 / R2>(lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)));
return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), R1 / R2};
}
template<auto R, typename Rep, typename Value>
@ -483,7 +487,7 @@ template<auto R, typename Rep, typename Value>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R, Rep>& q, const Value& v)
{
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
return make_quantity<R>(q.numerical_value_ref_in(get_unit(R)) / v);
return quantity{q.numerical_value_ref_in(get_unit(R)) / v, R};
}
template<typename Value, auto R, typename Rep>
@ -491,7 +495,7 @@ template<typename Value, auto R, typename Rep>
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, const Value&, Rep>
[[nodiscard]] constexpr Quantity auto operator/(const Value& v, const quantity<R, Rep>& q)
{
return make_quantity<::mp_units::one / R>(v / q.numerical_value_ref_in(get_unit(R)));
return quantity{v / q.numerical_value_ref_in(get_unit(R)), ::mp_units::one / R};
}
template<auto R1, typename Rep1, auto R2, typename Rep2>
@ -516,17 +520,6 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit);
}
// make_quantity
#if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17
template<auto R, typename Rep>
#else
template<Reference auto R, typename Rep>
#endif
[[nodiscard]] constexpr quantity<R, std::remove_cvref_t<Rep>> make_quantity(Rep&& v)
{
return quantity<R, std::remove_cvref_t<Rep>>(std::forward<Rep>(v));
}
} // namespace mp_units
namespace std {

View File

@ -88,13 +88,13 @@ public:
[[nodiscard]] static constexpr quantity_point min() noexcept
requires requires { quantity_type::min(); }
{
return quantity_point{quantity_type::min()};
return {quantity_type::min(), PO};
}
[[nodiscard]] static constexpr quantity_point max() noexcept
requires requires { quantity_type::max(); }
{
return quantity_point{quantity_type::max()};
return {quantity_type::max(), PO};
}
// construction, assignment, destruction
@ -102,6 +102,24 @@ public:
quantity_point(const quantity_point&) = default;
quantity_point(quantity_point&&) = default;
template<typename Q>
requires std::same_as<std::remove_cvref_t<Q>, quantity_type>
constexpr quantity_point(Q&& q, std::remove_const_t<decltype(PO)>) :
quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
{
}
template<typename Q, PointOrigin PO2>
requires Quantity<std::remove_cvref_t<Q>> && std::constructible_from<quantity_type, Q> &&
ReferenceOf<std::remove_const_t<decltype(std::remove_reference_t<Q>::reference)>, PO2::quantity_spec> &&
detail::SameAbsolutePointOriginAs<PO2, PO>
quantity_point(Q&& q, PO2) :
quantity_point(
quantity_point<std::remove_reference_t<Q>::reference, PO2{}, typename std::remove_reference_t<Q>::rep>{
std::forward<Q>(q), PO2{}})
{
}
template<QuantityPointOf<absolute_point_origin> QP>
requires std::constructible_from<quantity_type, typename QP::quantity_type>
// TODO add perfect forwarding
@ -142,7 +160,7 @@ public:
if constexpr (is_same_v<NewPO, std::remove_const_t<decltype(point_origin)>>)
return *this;
else
return make_quantity_point<new_origin>(*this - new_origin);
return ::mp_units::quantity_point{*this - new_origin, new_origin};
}
// data access
@ -173,14 +191,14 @@ public:
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, U{}), Rep>>
[[nodiscard]] constexpr QuantityPoint auto in(U) const
{
return make_quantity_point<PO>(quantity_ref_from(PO).in(U{}));
return ::mp_units::quantity_point{quantity_ref_from(PO).in(U{}), PO};
}
template<UnitCompatibleWith<unit, quantity_spec> U>
requires requires(quantity_type q) { value_cast<U{}>(q); }
[[nodiscard]] constexpr QuantityPoint auto force_in(U) const
{
return make_quantity_point<PO>(quantity_ref_from(PO).force_in(U{}));
return ::mp_units::quantity_point{quantity_ref_from(PO).force_in(U{}), PO};
}
// conversion operators
@ -234,7 +252,7 @@ public:
[[nodiscard]] constexpr quantity_point operator++(int)
requires requires { quantity_from_origin_is_an_implementation_detail_++; }
{
return quantity_point(quantity_from_origin_is_an_implementation_detail_++);
return {quantity_from_origin_is_an_implementation_detail_++, PO};
}
template<typename QP>
@ -249,7 +267,7 @@ public:
[[nodiscard]] constexpr quantity_point operator--(int)
requires requires { quantity_from_origin_is_an_implementation_detail_--; }
{
return quantity_point(quantity_from_origin_is_an_implementation_detail_--);
return {quantity_from_origin_is_an_implementation_detail_--, PO};
}
// compound assignment operators
@ -270,25 +288,12 @@ public:
qp.quantity_from_origin_is_an_implementation_detail_ -= q;
return std::forward<QP>(qp);
}
private:
#if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17
template<auto PO2, typename Q>
#else
template<PointOrigin auto PO2, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO2.quantity_spec>
#endif
friend constexpr quantity_point<Q::reference, PO2, typename Q::rep> make_quantity_point(Q&&);
template<Quantity Q>
requires std::constructible_from<quantity_type, Q> &&
ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO.quantity_spec>
constexpr explicit quantity_point(Q&& q) : quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
{
}
};
// CTAD
template<Quantity Q, PointOriginFor<Q::quantity_spec> PO>
quantity_point(Q q, PO) -> quantity_point<Q::reference, PO{}, typename Q::rep>;
template<QuantityPointLike QP>
explicit(
is_specialization_of<decltype(quantity_point_like_traits<QP>::to_quantity(std::declval<QP>())), convert_explicitly>)
@ -303,7 +308,7 @@ template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
const quantity<R2, Rep2>& q)
requires requires { qp.quantity_ref_from(PO1) + q; }
{
return make_quantity_point<PO1>(qp.quantity_ref_from(PO1) + q);
return quantity_point{qp.quantity_ref_from(PO1) + q, PO1};
}
template<auto R1, typename Rep1, auto R2, auto PO2, typename Rep2>
@ -320,7 +325,7 @@ template<PointOrigin PO, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec>
[[nodiscard]] constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, Q&& q)
{
return make_quantity_point<PO{}>(std::forward<Q>(q));
return quantity_point{std::forward<Q>(q), PO{}};
}
template<Quantity Q, PointOrigin PO>
@ -337,7 +342,7 @@ template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
const quantity<R2, Rep2>& q)
requires requires { qp.quantity_ref_from(PO1) - q; }
{
return make_quantity_point<PO1>(qp.quantity_ref_from(PO1) - q);
return quantity_point{qp.quantity_ref_from(PO1) - q, PO1};
}
template<PointOrigin PO, Quantity Q>
@ -429,16 +434,4 @@ template<QuantityPoint QP1, QuantityPointOf<QP1::absolute_point_origin> QP2>
return lhs - lhs.absolute_point_origin == rhs - rhs.absolute_point_origin;
}
// make_quantity_point
#if defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 17
template<auto PO, typename Q>
#else
template<PointOrigin auto PO, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO.quantity_spec>
#endif
[[nodiscard]] constexpr quantity_point<Q::reference, PO, typename Q::rep> make_quantity_point(Q&& q)
{
return quantity_point<Q::reference, PO, typename Q::rep>(std::forward<Q>(q));
}
} // namespace mp_units

View File

@ -119,8 +119,8 @@ struct quantity_spec_interface {
requires Quantity<std::remove_cvref_t<Q>> &&
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, self))
{
return make_quantity<reference<self, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
reference<self, std::remove_cvref_t<Q>::unit>{}};
}
#else
template<typename Self_ = Self, UnitOf<Self_{}> U>
@ -134,8 +134,8 @@ struct quantity_spec_interface {
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
reference<Self{}, std::remove_cvref_t<Q>::unit>{}};
}
#endif
};
@ -311,8 +311,8 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
reference<Self{}, std::remove_cvref_t<Q>::unit> {}};
}
#endif
};

View File

@ -179,14 +179,14 @@ template<typename Rep, Reference R>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
[[nodiscard]] constexpr quantity<R{}, std::remove_cvref_t<Rep>> operator*(Rep&& lhs, R)
{
return make_quantity<R{}>(std::forward<Rep>(lhs));
return quantity{std::forward<Rep>(lhs), R{}};
}
template<typename Rep, Reference R>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
[[nodiscard]] constexpr quantity<inverse(R{}), std::remove_cvref_t<Rep>> operator/(Rep&& lhs, R)
{
return make_quantity<inverse(R{})>(std::forward<Rep>(lhs));
return quantity{std::forward<Rep>(lhs), inverse(R{})};
}
template<Reference R, typename Rep>
@ -201,16 +201,16 @@ template<typename Q, Reference R>
requires Quantity<std::remove_cvref_t<Q>>
[[nodiscard]] constexpr Quantity auto operator*(Q&& q, R)
{
return make_quantity<std::remove_cvref_t<Q>::reference * R{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
std::remove_cvref_t<Q>::reference * R{}};
}
template<typename Q, Reference R>
requires Quantity<std::remove_cvref_t<Q>>
[[nodiscard]] constexpr Quantity auto operator/(Q&& q, R)
{
return make_quantity<std::remove_cvref_t<Q>::reference / R{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
std::remove_cvref_t<Q>::reference / R{}};
}
template<Reference R, typename Q>

View File

@ -63,8 +63,9 @@ template<std::intmax_t Num, std::intmax_t Den = 1, auto R, typename Rep>
return q;
} else {
using std::pow;
return make_quantity<pow<Num, Den>(R)>(
static_cast<Rep>(pow(q.numerical_value_ref_in(q.unit), static_cast<double>(Num) / static_cast<double>(Den))));
return {
static_cast<Rep>(pow(q.numerical_value_ref_in(q.unit), static_cast<double>(Num) / static_cast<double>(Den))),
pow<Num, Den>(R)};
}
}
@ -82,7 +83,7 @@ template<auto R, typename Rep>
requires { std::sqrt(q.numerical_value_ref_in(q.unit)); }
{
using std::sqrt;
return make_quantity<sqrt(R)>(static_cast<Rep>(sqrt(q.numerical_value_ref_in(q.unit))));
return {static_cast<Rep>(sqrt(q.numerical_value_ref_in(q.unit))), sqrt(R)};
}
/**
@ -99,7 +100,7 @@ template<auto R, typename Rep>
requires { std::cbrt(q.numerical_value_ref_in(q.unit)); }
{
using std::cbrt;
return make_quantity<cbrt(R)>(static_cast<Rep>(cbrt(q.numerical_value_ref_in(q.unit))));
return {static_cast<Rep>(cbrt(q.numerical_value_ref_in(q.unit))), cbrt(R)};
}
/**
@ -117,7 +118,7 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
{
using std::exp;
return value_cast<get_unit(R)>(
make_quantity<detail::clone_reference_with<one>(R)>(static_cast<Rep>(exp(q.force_numerical_value_in(q.unit)))));
quantity{static_cast<Rep>(exp(q.force_numerical_value_in(q.unit))), detail::clone_reference_with<one>(R)});
}
/**
@ -132,7 +133,7 @@ template<auto R, typename Rep>
requires { std::abs(q.numerical_value_ref_in(q.unit)); }
{
using std::abs;
return make_quantity<R>(static_cast<Rep>(abs(q.numerical_value_ref_in(q.unit))));
return {static_cast<Rep>(abs(q.numerical_value_ref_in(q.unit))), R};
}
/**
@ -147,7 +148,7 @@ template<Representation Rep, Reference R>
requires requires { std::numeric_limits<Rep>::epsilon(); }
[[nodiscard]] constexpr quantity<R{}, Rep> epsilon(R r) noexcept
{
return make_quantity<r>(static_cast<Rep>(std::numeric_limits<Rep>::epsilon()));
return {static_cast<Rep>(std::numeric_limits<Rep>::epsilon()), r};
}
/**
@ -174,11 +175,10 @@ template<Unit auto To, auto R, typename Rep>
if constexpr (treat_as_floating_point<Rep>) {
using std::floor;
if constexpr (To == get_unit(R)) {
return make_quantity<detail::clone_reference_with<To>(R)>(
static_cast<Rep>(floor(q.numerical_value_ref_in(q.unit))));
return {static_cast<Rep>(floor(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with<To>(R)};
} else {
return handle_signed_results(
make_quantity<detail::clone_reference_with<To>(R)>(static_cast<Rep>(floor(q.force_numerical_value_in(To)))));
quantity{static_cast<Rep>(floor(q.force_numerical_value_in(To))), detail::clone_reference_with<To>(R)});
}
} else {
if constexpr (To == get_unit(R)) {
@ -213,11 +213,10 @@ template<Unit auto To, auto R, typename Rep>
if constexpr (treat_as_floating_point<Rep>) {
using std::ceil;
if constexpr (To == get_unit(R)) {
return make_quantity<detail::clone_reference_with<To>(R)>(
static_cast<Rep>(ceil(q.numerical_value_ref_in(q.unit))));
return {static_cast<Rep>(ceil(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with<To>(R)};
} else {
return handle_signed_results(
make_quantity<detail::clone_reference_with<To>(R)>(static_cast<Rep>(ceil(q.force_numerical_value_in(To)))));
quantity{static_cast<Rep>(ceil(q.force_numerical_value_in(To))), detail::clone_reference_with<To>(R)});
}
} else {
if constexpr (To == get_unit(R)) {
@ -248,8 +247,7 @@ template<Unit auto To, auto R, typename Rep>
if constexpr (To == get_unit(R)) {
if constexpr (treat_as_floating_point<Rep>) {
using std::round;
return make_quantity<detail::clone_reference_with<To>(R)>(
static_cast<Rep>(round(q.numerical_value_ref_in(q.unit))));
return {static_cast<Rep>(round(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with<To>(R)};
} else {
return q.force_in(To);
}
@ -299,7 +297,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref);
using std::hypot;
return make_quantity<ref>(hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)));
return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref};
}
/**
@ -323,7 +321,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2, auto R3, typename Rep3>
constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref);
using std::hypot;
return make_quantity<ref>(hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)));
return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), ref};
}
namespace isq {
@ -338,9 +336,9 @@ template<ReferenceOf<angular_measure> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(sin(q.force_numerical_value_in(si::radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(sin(value_cast<rep>(q).numerical_value_in(si::radian)));
return quantity{sin(value_cast<rep>(q).numerical_value_in(si::radian)), one};
} else
return make_quantity<one>(sin(q.numerical_value_in(si::radian)));
return quantity{sin(q.numerical_value_in(si::radian)), one};
}
template<ReferenceOf<angular_measure> auto R, typename Rep>
@ -353,9 +351,9 @@ template<ReferenceOf<angular_measure> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(cos(q.force_numerical_value_in(si::radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(cos(value_cast<rep>(q).numerical_value_in(si::radian)));
return quantity{cos(value_cast<rep>(q).numerical_value_in(si::radian)), one};
} else
return make_quantity<one>(cos(q.numerical_value_in(si::radian)));
return quantity{cos(q.numerical_value_in(si::radian)), one};
}
template<ReferenceOf<angular_measure> auto R, typename Rep>
@ -368,9 +366,9 @@ template<ReferenceOf<angular_measure> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(tan(q.force_numerical_value_in(si::radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(tan(value_cast<rep>(q).numerical_value_in(si::radian)));
return quantity{tan(value_cast<rep>(q).numerical_value_in(si::radian)), one};
} else
return make_quantity<one>(tan(q.numerical_value_in(si::radian)));
return quantity{tan(q.numerical_value_in(si::radian)), one};
}
template<ReferenceOf<dimensionless> auto R, typename Rep>
@ -383,9 +381,9 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(asin(q.force_numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<si::radian>(asin(value_cast<rep>(q).numerical_value_in(one)));
return quantity{asin(value_cast<rep>(q).numerical_value_in(one)), si::radian};
} else
return make_quantity<si::radian>(asin(q.numerical_value_in(one)));
return quantity{asin(q.numerical_value_in(one)), si::radian};
}
template<ReferenceOf<dimensionless> auto R, typename Rep>
@ -398,9 +396,9 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(acos(q.force_numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<si::radian>(acos(value_cast<rep>(q).numerical_value_in(one)));
return quantity{acos(value_cast<rep>(q).numerical_value_in(one)), si::radian};
} else
return make_quantity<si::radian>(acos(q.numerical_value_in(one)));
return quantity{acos(q.numerical_value_in(one)), si::radian};
}
template<ReferenceOf<dimensionless> auto R, typename Rep>
@ -413,9 +411,9 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(atan(q.force_numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<si::radian>(atan(value_cast<rep>(q).numerical_value_in(one)));
return quantity{atan(value_cast<rep>(q).numerical_value_in(one)), si::radian};
} else
return make_quantity<si::radian>(atan(q.numerical_value_in(one)));
return quantity{atan(q.numerical_value_in(one)), si::radian};
}
} // namespace isq
@ -432,9 +430,9 @@ template<ReferenceOf<angle> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(sin(q.force_numerical_value_in(radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(sin(value_cast<rep>(q).numerical_value_in(radian)));
return quantity{sin(value_cast<rep>(q).numerical_value_in(radian)), one};
} else
return make_quantity<one>(sin(q.numerical_value_in(radian)));
return quantity{sin(q.numerical_value_in(radian)), one};
}
template<ReferenceOf<angle> auto R, typename Rep>
@ -447,9 +445,9 @@ template<ReferenceOf<angle> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(cos(q.force_numerical_value_in(radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(cos(value_cast<rep>(q).numerical_value_in(radian)));
return quantity{cos(value_cast<rep>(q).numerical_value_in(radian)), one};
} else
return make_quantity<one>(cos(q.numerical_value_in(radian)));
return quantity{cos(q.numerical_value_in(radian)), one};
}
template<ReferenceOf<angle> auto R, typename Rep>
@ -462,9 +460,9 @@ template<ReferenceOf<angle> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(tan(q.force_numerical_value_in(radian)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<one>(tan(value_cast<rep>(q).numerical_value_in(radian)));
return quantity{tan(value_cast<rep>(q).numerical_value_in(radian)), one};
} else
return make_quantity<one>(tan(q.numerical_value_in(radian)));
return quantity{tan(q.numerical_value_in(radian)), one};
}
template<ReferenceOf<dimensionless> auto R, typename Rep>
@ -477,9 +475,9 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(asin(q.force_numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<radian>(asin(value_cast<rep>(q).numerical_value_in(one)));
return quantity{asin(value_cast<rep>(q).numerical_value_in(one)), radian};
} else
return make_quantity<radian>(asin(q.numerical_value_in(one)));
return quantity{asin(q.numerical_value_in(one)), radian};
}
template<ReferenceOf<dimensionless> auto R, typename Rep>
@ -492,9 +490,9 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(acos(q.force_numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<radian>(acos(value_cast<rep>(q).numerical_value_in(one)));
return quantity{acos(value_cast<rep>(q).numerical_value_in(one)), radian};
} else
return make_quantity<radian>(acos(q.numerical_value_in(one)));
return quantity{acos(q.numerical_value_in(one)), radian};
}
template<ReferenceOf<dimensionless> auto R, typename Rep>
@ -507,9 +505,9 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
// check what is the return type when called with the integral value
using rep = decltype(atan(q.force_numerical_value_in(one)));
// use this type ahead of calling the function to prevent narrowing if a unit conversion is needed
return make_quantity<radian>(atan(value_cast<rep>(q).numerical_value_in(one)));
return quantity{atan(value_cast<rep>(q).numerical_value_in(one)), radian};
} else
return make_quantity<radian>(atan(q.numerical_value_in(one)));
return quantity{atan(q.numerical_value_in(one)), radian};
}
} // namespace angular