Skip to content

Commit

Permalink
feat: 💥 RepresentationOf concept now also accepts a QuantitySpec
Browse files Browse the repository at this point in the history
…and accepts any representation character for quantity kinds
  • Loading branch information
mpusz committed Nov 7, 2024
1 parent 75b50b8 commit da50348
Show file tree
Hide file tree
Showing 14 changed files with 88 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ As we remember, the `quantity` class template is defined as follows:

```cpp
template<Reference auto R,
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity;
```

Expand Down
19 changes: 16 additions & 3 deletions docs/users_guide/framework_basics/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,28 @@ A `Reference` can either be:
[value of a quantity](../../appendix/glossary.md#quantity-value).


### `RepresentationOf<T, Ch>` { #RepresentationOf }
### `RepresentationOf<T, V>` { #RepresentationOf }

`RepresentationOf` concept is satisfied by all `Representation` types that are of a specified
[quantity character](../../appendix/glossary.md#character) `Ch`.
`RepresentationOf` concept is satisfied:

- if the type of `V` satisfies [`QuantitySpec`](#QuantitySpec):

- by all [`Representation`](#Representation) types when `V` describes
a [quantity kind](../../appendix/glossary.md#kind),
- otherwise, by [`Representation`](#Representation) types that are of
a [quantity character](../../appendix/glossary.md#character) associated with a provided
quantity specification `V`.

- if `V` is of `quantity_character` type:

- by [`Representation`](#Representation) types that are of a provided
[quantity character](../../appendix/glossary.md#character).

This comment has been minimized.

Copy link
@JohelEGP

JohelEGP Nov 7, 2024

Collaborator

This seems backwards to me.
We don't say that int represents a scalar quantity character.
Isn't the character of a quantity suppose to describe the set of its numerical value?

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 7, 2024

Author Owner

It was never supposed to be a set. ISQ is always explicit about the character of a given quantity. The only problem that we had was for quantity kinds that behave as any quantity from a tree. With this change, we removed this problem.

Now, we allow a kind to have any character, but a specific character is needed when converted to a specific quantity.

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 7, 2024

Author Owner

In the framework, I actually never need V of a quantity_character type, but I think it is useful for the users to be able to static_assert if a specific representation type satisfies a given character (see concepts_test.cpp).

Do you agree with that? Or maybe we should simplify the concept and remove this extension?

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

Isn't the character of a quantity suppose to describe the set of its numerical value?

Do you mean that instead of the opt-in with traits you would prefer to detect if something has a proper representation based on its interface? This makes sense now as we list concrete interfaces for each category. It was not the case before.

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

But still there may be some issues. For example, a double will qualify as complex. Which might be fine, but I am not 100% sure if it will not backfire.

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

Well, maybe it is not an issue, as we will add more to ComplexRepresentation soon:

  { re(a) } -> Scalar;
  { im(a) } -> Scalar;
  { mod(a) } -> Scalar;
  { arg(a) } -> Scalar;
  { conj(a) } -> Complex;

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

But the concepts can't be recursive, so how would we check if the returned expression type has proper semantics? Checking for a type trait was good enough in the proposed implementation.

This comment has been minimized.

Copy link
@JohelEGP

JohelEGP Nov 8, 2024

Collaborator

That's what I use std::common_with for.

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

I think I can't replace Scalar with std::common_with in a Complex concept definition?

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

The only solution would be something like:

{ re(a) } -> std::common_with<value_type_t<T>>;

This comment has been minimized.

Copy link
@JohelEGP

JohelEGP Nov 8, 2024

Collaborator

Factored out that "scalar with" part.
A scalar is scalar with itself.
A complex is scalar with its scalar.
Same for vector and tensor.

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

This brings me to a question that I have for a while. Should we expose a value_type customization point? For example, there are some types that provide both value_type and an element_type. Before, I favored value_type but with your implementation we removed this.

Also, some types do not expose any of those and might not be possible to change by the users (types from external libraries beyond our control).

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

A complex is scalar with its scalar.

The problem is how to obtain "its scalar" ;-) See above.

This comment has been minimized.

Copy link
@JohelEGP

JohelEGP Nov 8, 2024

Collaborator

Also, some types do not expose any of those and might not be possible to change by the users (types from external libraries beyond our control).

That's why they can specialize it as long as it depends on one of their types.
If a user specializes std::trait<extlib::type<my_type>>,
even if the library later specializes std::trait<extlib::type<T>>,
the former will keep on being more specialized.

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

Sure! But as of today, it is not possible to specialize it:

namespace detail {
template<typename T>
struct value_type_impl {
using type = T;
};
template<typename T>
requires requires { typename wrapped_type_t<T>; }
struct value_type_impl<T> {
using type = wrapped_type_t<T>;
};
} // namespace detail
template<typename T>
requires std::is_object_v<T>
using value_type_t = detail::value_type_impl<T>::type;

This comment has been minimized.

Copy link
@mpusz

mpusz Nov 8, 2024

Author Owner

We should move it to mp_units and possibly to customization_points.h if we want to expose it as a customization point.


A user can declare a custom representation type to be of a specific character by providing the specialization
with `true` for one or more of the following variable templates:

- `is_scalar<T>`
- `is_complex<T>`
- `is_vector<T>`
- `is_tensor<T>`

Expand Down
4 changes: 2 additions & 2 deletions docs/users_guide/framework_basics/design_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ This is why a `quantity` class template is defined in the library as:
```cpp
template<Reference auto R,
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity;
```

Expand Down Expand Up @@ -365,7 +365,7 @@ In the **mp-units** library, the quantity point is implemented as:
```cpp
template<Reference auto R,
PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity_point;
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ In the **mp-units** library, a quantity is represented with the following class

```cpp
template<Reference auto R,
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity;
```

Expand Down
2 changes: 1 addition & 1 deletion docs/users_guide/framework_basics/the_affine_space.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ origin:
```cpp
template<Reference auto R,
PointOriginFor<get_quantity_spec(R)> auto PO = default_point_origin(R),
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity_point;
```

Expand Down
4 changes: 2 additions & 2 deletions src/core/include/mp-units/framework/construction_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace mp_units {

template<Reference R>
struct delta_ {
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
[[nodiscard]] constexpr quantity<MP_UNITS_EXPRESSION_WORKAROUND(R{}), Rep> operator()(FwdRep&& lhs) const
{
return quantity{std::forward<FwdRep>(lhs), R{}};
Expand All @@ -48,7 +48,7 @@ struct delta_ {

template<Reference R>
struct absolute_ {
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
[[nodiscard]] constexpr quantity_point<MP_UNITS_EXPRESSION_WORKAROUND(R{}), default_point_origin(R{}), Rep>
operator()(FwdRep&& lhs) const
{
Expand Down
78 changes: 38 additions & 40 deletions src/core/include/mp-units/framework/quantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,15 @@ concept QuantityConvertibleTo =
// deduced thus the function is evaluated here and may emit truncating conversion or other warnings)
requires(QFrom q) { sudo_cast<QTo>(q); };

template<quantity_character Ch, typename Func, typename T, typename U>
concept InvokeResultOf = std::regular_invocable<Func, T, U> && RepresentationOf<std::invoke_result_t<Func, T, U>, Ch>;
template<auto QS, typename Func, typename T, typename U>
concept InvokeResultOf = QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && std::regular_invocable<Func, T, U> &&
RepresentationOf<std::invoke_result_t<Func, T, U>, QS>;

template<typename Func, typename Q1, typename Q2,
quantity_character Ch = std::invoke_result_t<Func, std::remove_const_t<decltype(Q1::quantity_spec)>,
std::remove_const_t<decltype(Q2::quantity_spec)>>::character>
concept InvocableQuantities =
Quantity<Q1> && Quantity<Q2> && InvokeResultOf<Ch, Func, typename Q1::rep, typename Q2::rep>;
auto QS = std::invoke_result_t<Func, std::remove_const_t<decltype(Q1::quantity_spec)>,
std::remove_const_t<decltype(Q2::quantity_spec)>>{}>
concept InvocableQuantities = QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && Quantity<Q1> && Quantity<Q2> &&
InvokeResultOf<QS, Func, typename Q1::rep, typename Q2::rep>;

// TODO remove the following when clang diagnostics improve
// https://github.com/llvm/llvm-project/issues/96660
Expand All @@ -104,7 +105,7 @@ concept CommonlyInvocableQuantities =
Quantity<Q1> && Quantity<Q2> && HaveCommonReference<Q1::reference, Q2::reference> &&
std::convertible_to<Q1, common_quantity_for<Func, Q1, Q2>> &&
std::convertible_to<Q2, common_quantity_for<Func, Q1, Q2>> &&
InvocableQuantities<Func, Q1, Q2, get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character>;
InvocableQuantities<Func, Q1, Q2, get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>;

template<auto R1, auto R2, typename Rep1, typename Rep2>
concept SameValueAs = (equivalent(get_unit(R1), get_unit(R2))) && std::convertible_to<Rep1, Rep2>;
Expand All @@ -128,7 +129,7 @@ MP_UNITS_EXPORT_BEGIN
* @tparam R a reference of the quantity providing all information about quantity properties
* @tparam Rep a type to be used to represent values of a quantity
*/
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep = double>
template<Reference auto R, RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity {
public:
Rep numerical_value_is_an_implementation_detail_; ///< needs to be public for a structural type
Expand Down Expand Up @@ -227,14 +228,14 @@ class quantity {
return quantity<detail::make_reference(quantity_spec, ToU{}), Rep>{*this};
}

template<RepresentationOf<quantity_spec.character> ToRep>
template<RepresentationOf<quantity_spec> ToRep>
requires detail::QuantityConvertibleTo<quantity, quantity<reference, ToRep>>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto in() const
{
return quantity<reference, ToRep>{*this};
}

template<RepresentationOf<quantity_spec.character> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires detail::QuantityConvertibleTo<quantity, quantity<detail::make_reference(quantity_spec, ToU{}), ToRep>>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto in(ToU) const
{
Expand All @@ -248,14 +249,14 @@ class quantity {
return value_cast<ToU{}>(*this);
}

template<RepresentationOf<quantity_spec.character> ToRep>
template<RepresentationOf<quantity_spec> ToRep>
requires requires(quantity q) { value_cast<ToRep>(q); }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto force_in() const
{
return value_cast<ToRep>(*this);
}

template<RepresentationOf<quantity_spec.character> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires requires(quantity q) { value_cast<ToU{}, ToRep>(q); }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto force_in(ToU) const
{
Expand Down Expand Up @@ -474,17 +475,15 @@ class quantity {
ret::reference};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::plus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const Value& rhs)
{
return lhs + ::mp_units::quantity{rhs};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::plus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const Q& rhs)
{
return ::mp_units::quantity{lhs} + rhs;
Expand All @@ -501,17 +500,15 @@ class quantity {
ret::reference};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::minus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator-(const Q& lhs, const Value& rhs)
{
return lhs - ::mp_units::quantity{rhs};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::minus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const Q& rhs)
{
return ::mp_units::quantity{lhs} - rhs;
Expand All @@ -530,17 +527,15 @@ class quantity {
ret::reference};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::modulus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator%(const Q& lhs, const Value& rhs)
{
return lhs % ::mp_units::quantity{rhs};
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
requires(Q::unit == ::mp_units::one) &&
detail::InvokeResultOf<quantity_character::scalar, std::modulus<>, Rep, const Value&>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator%(const Value& lhs, const Q& rhs)
{
return ::mp_units::quantity{lhs} % rhs;
Expand All @@ -555,15 +550,15 @@ class quantity {

template<std::derived_from<quantity> Q, typename Value>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec.character, std::multiplies<>, Rep, const Value&>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, Rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Q& q, const Value& v)
{
return ::mp_units::quantity{q.numerical_value_ref_in(unit) * v, R};
}

template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec.character, std::multiplies<>, const Value&, Rep>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, const Value&, Rep>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Value& v, const Q& q)
{
return ::mp_units::quantity{v * q.numerical_value_ref_in(unit), R};
Expand All @@ -579,7 +574,7 @@ class quantity {

template<std::derived_from<quantity> Q, typename Value>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec.character, std::divides<>, Rep, const Value&>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, Rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator/(const Q& q, const Value& v)
{
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
Expand All @@ -588,7 +583,7 @@ class quantity {

template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec.character, std::divides<>, const Value&, Rep>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, const Value&, Rep>
[[nodiscard]] friend constexpr QuantityOf<inverse(quantity_spec)> auto operator/(const Value& v, const Q& q)
{
return ::mp_units::quantity{v / q.numerical_value_ref_in(unit), ::mp_units::one / R};
Expand All @@ -605,7 +600,7 @@ class quantity {
return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit);
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && std::equality_comparable_with<Rep, Value>
[[nodiscard]] friend constexpr bool operator==(const Q& lhs, const Value& rhs)
{
Expand All @@ -623,7 +618,7 @@ class quantity {
return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit);
}

template<std::derived_from<quantity> Q, RepresentationOf<quantity_character::scalar> Value>
template<std::derived_from<quantity> Q, Representation Value>
requires(Q::unit == ::mp_units::one) && std::three_way_comparable_with<Rep, Value>
[[nodiscard]] friend constexpr auto operator<=>(const Q& lhs, const Value& rhs)
{
Expand All @@ -650,18 +645,21 @@ template<mp_units::Quantity Q1, mp_units::Quantity Q2>
requires requires {
{ mp_units::get_common_reference(Q1::reference, Q2::reference) } -> mp_units::Reference;
typename std::common_type_t<typename Q1::rep, typename Q2::rep>;
requires mp_units::RepresentationOf<std::common_type_t<typename Q1::rep, typename Q2::rep>,
mp_units::get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>;
}
struct std::common_type<Q1, Q2> {
using type = mp_units::quantity<mp_units::get_common_reference(Q1::reference, Q2::reference),
std::common_type_t<typename Q1::rep, typename Q2::rep>>;
};

template<mp_units::Quantity Q, mp_units::RepresentationOf<mp_units::quantity_character::scalar> Value>
requires(Q::unit == mp_units::one) && requires { typename std::common_type_t<typename Q::rep, Value>; }
template<mp_units::Quantity Q, mp_units::Representation Value>
requires(Q::unit == mp_units::one) &&
requires { typename mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>; }
struct std::common_type<Q, Value> {
using type = mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>;
};

template<mp_units::Quantity Q, mp_units::RepresentationOf<mp_units::quantity_character::scalar> Value>
requires(Q::unit == mp_units::one) && requires { typename std::common_type_t<typename Q::rep, Value>; }
template<mp_units::Quantity Q, mp_units::Representation Value>
requires requires { typename std::common_type<Q, Value>; }
struct std::common_type<Value, Q> : std::common_type<Q, Value> {};
2 changes: 1 addition & 1 deletion src/core/include/mp-units/framework/quantity_concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

namespace mp_units {

MP_UNITS_EXPORT template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep>
MP_UNITS_EXPORT template<Reference auto R, RepresentationOf<get_quantity_spec(R)> Rep>
class quantity;

namespace detail {
Expand Down
10 changes: 5 additions & 5 deletions src/core/include/mp-units/framework/quantity_point.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ template<PointOrigin PO>
* @tparam Rep a type to be used to represent values of a quantity point
*/
MP_UNITS_EXPORT template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO = default_point_origin(R),
RepresentationOf<get_quantity_spec(R).character> Rep = double>
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity_point {
public:
// member types and values
Expand Down Expand Up @@ -329,14 +329,14 @@ class quantity_point {
return ::mp_units::quantity_point{quantity_ref_from(point_origin).in(ToU{}), point_origin};
}

template<RepresentationOf<quantity_spec.character> ToRep>
template<RepresentationOf<quantity_spec> ToRep>
requires detail::QuantityConvertibleTo<quantity_type, quantity<reference, ToRep>>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in() const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template in<ToRep>(), point_origin};
}

template<RepresentationOf<quantity_spec.character> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, ToU{}), ToRep>>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in(ToU) const
{
Expand All @@ -350,14 +350,14 @@ class quantity_point {
return ::mp_units::quantity_point{quantity_ref_from(point_origin).force_in(ToU{}), point_origin};
}

template<RepresentationOf<quantity_spec.character> ToRep>
template<RepresentationOf<quantity_spec> ToRep>
requires requires(quantity_type q) { value_cast<ToRep>(q); }
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in() const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template force_in<ToRep>(), point_origin};
}

template<RepresentationOf<quantity_spec.character> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires requires(quantity_type q) { value_cast<ToU{}, ToRep>(q); }
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in(ToU) const
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ MP_UNITS_EXPORT template<typename T, auto QS>
concept PointOriginFor = PointOrigin<T> && QuantitySpecOf<MP_UNITS_REMOVE_CONST(decltype(QS)), T::_quantity_spec_>;

MP_UNITS_EXPORT template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R).character> Rep>
RepresentationOf<get_quantity_spec(R)> Rep>
class quantity_point;

namespace detail {
Expand Down
Loading

0 comments on commit da50348

Please sign in to comment.