Skip to content

Commit

Permalink
Merge pull request #577 from mpusz/hidden_friends
Browse files Browse the repository at this point in the history
refactor: binary operators of `quantity` and `quantity_point` are now hidden friends
  • Loading branch information
mpusz authored Jul 11, 2024
2 parents c8849e5 + 175fd04 commit dd52808
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 205 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
- refactor: `terminate` replaced with `abort` and a header file added
- refactor: most `std::remove_const_t` removed and some replaced with the GCC-specific workaround
- refactor: not needed `remove_reference_t` and `remove_cvref_t` removed
- refactor: binary operators of `quantity` and `quantity_point` are now hidden friends
- fix: `QuantityLike` conversions required `Q::rep` instead of using one provided by `quantity_like_traits`
- fix: `QuantitySpec[Unit]` replaced with `make_reference` in `value_cast`
- fix: `ice_point` is now defined with the integral offset from `absolute_zero`
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")

set(projectPrefix MP_UNITS_)

option(${projectPrefix}DEV_BUILD_LA "Build code depending on the linear algebra library" ON)
option(${projectPrefix}DEV_BUILD_LA "Build code depending on the linear algebra library" OFF)
option(${projectPrefix}DEV_IWYU "Enables include-what-you-use" OFF)
option(${projectPrefix}DEV_CLANG_TIDY "Enables clang-tidy" OFF)

Expand Down
3 changes: 2 additions & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ def _build_all(self):

@property
def _skip_la(self):
return bool(self.conf.get("user.mp-units.build:skip_la", default=False))
# broken until https://github.com/BobSteagall/wg21/issues/77 is fixed
return bool(self.conf.get("user.mp-units.build:skip_la", default=True))

@property
def _run_clang_tidy(self):
Expand Down
2 changes: 1 addition & 1 deletion docs/getting_started/installation_and_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}

[`user.mp-units.build:skip_la`](#user-skip-la){ #user-skip-la }

: [:octicons-tag-24: 2.2.0][conan skip la support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
: [:octicons-tag-24: 2.2.0][conan skip la support] · :octicons-milestone-24: `True`/`False` (Default: `True`)

If `user.mp-units.build:all` is enabled, among others, Conan installs the external
[wg21-linear_algebra](https://conan.io/center/recipes/wg21-linear_algebra)
Expand Down
212 changes: 107 additions & 105 deletions src/core/include/mp-units/framework/quantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,124 +461,126 @@ class quantity {
lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs);
}
};

// CTAD
template<typename Value, Reference R>
requires RepresentationOf<Value, get_quantity_spec(R{}).character>
quantity(Value v, R) -> quantity<R{}, Value>;
// binary operators on quantities
template<auto R2, typename Rep2>
requires detail::CommonlyInvocableQuantities<std::plus<>, quantity, quantity<R2, Rep2>>
[[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const quantity<R2, Rep2>& rhs)
{
using ret = detail::common_quantity_for<std::plus<>, quantity, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return ::mp_units::quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
}

template<QuantityLike Q>
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>;
template<auto R2, typename Rep2>
requires detail::CommonlyInvocableQuantities<std::minus<>, quantity, quantity<R2, Rep2>>
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const quantity<R2, Rep2>& rhs)
{
using ret = detail::common_quantity_for<std::minus<>, quantity, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return ::mp_units::quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
}

// binary operators on quantities
template<auto R1, typename Rep1, auto R2, typename Rep2>
requires detail::CommonlyInvocableQuantities<std::plus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator+(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
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 quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
}
template<auto R2, typename Rep2>
requires(!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Rep2>) &&
detail::CommonlyInvocableQuantities<std::modulus<>, quantity, quantity<R2, Rep2>>
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const quantity<R2, Rep2>& rhs)
{
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
using ret = detail::common_quantity_for<std::modulus<>, quantity, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return ::mp_units::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::CommonlyInvocableQuantities<std::minus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator-(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
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 quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
}
template<auto R2, typename Rep2>
requires detail::InvocableQuantities<std::multiplies<>, quantity, quantity<R2, Rep2>>
[[nodiscard]] friend constexpr Quantity auto operator*(const quantity& lhs, const quantity<R2, Rep2>& rhs)
{
return ::mp_units::quantity{lhs.numerical_value_ref_in(get_unit(R)) * rhs.numerical_value_ref_in(get_unit(R2)),
R * R2};
}

template<auto R1, typename Rep1, auto R2, typename Rep2>
requires(!treat_as_floating_point<Rep1>) && (!treat_as_floating_point<Rep2>) &&
detail::CommonlyInvocableQuantities<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator%(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
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 quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
}
template<typename Value>
requires(!Quantity<Value>) && (!Reference<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, Rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<get_quantity_spec(R)> auto operator*(const quantity& q, const Value& v)
{
return ::mp_units::quantity{q.numerical_value_ref_in(get_unit(R)) * v, R};
}

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 quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), R1 * R2};
}
template<typename Value>
requires(!Quantity<Value>) && (!Reference<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, const Value&, Rep>
[[nodiscard]] friend constexpr QuantityOf<get_quantity_spec(R)> auto operator*(const Value& v, const quantity& q)
{
return ::mp_units::quantity{v * q.numerical_value_ref_in(get_unit(R)), R};
}

template<auto R, typename Rep, typename Value>
requires(!Quantity<Value>) && (!Reference<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, Rep, const Value&>
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator*(const quantity<R, Rep>& q, const Value& v)
{
return quantity{q.numerical_value_ref_in(get_unit(R)) * v, R};
}
template<auto R2, typename Rep2>
requires detail::InvocableQuantities<std::divides<>, quantity, quantity<R2, Rep2>>
[[nodiscard]] friend constexpr Quantity auto operator/(const quantity& lhs, const quantity<R2, Rep2>& rhs)
{
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
return ::mp_units::quantity{lhs.numerical_value_ref_in(get_unit(R)) / rhs.numerical_value_ref_in(get_unit(R2)),
R / R2};
}

template<typename Value, auto R, typename Rep>
requires(!Quantity<Value>) && (!Reference<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, const Value&, Rep>
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator*(const Value& v, const quantity<R, Rep>& q)
{
return quantity{v * q.numerical_value_ref_in(get_unit(R)), R};
}
template<typename Value>
requires(!Quantity<Value>) && (!Reference<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, Rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<get_quantity_spec(R)> auto operator/(const quantity& q, const Value& v)
{
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
return ::mp_units::quantity{q.numerical_value_ref_in(get_unit(R)) / v, R};
}

template<auto R1, typename Rep1, auto R2, typename Rep2>
requires detail::InvocableQuantities<std::divides<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), R1 / R2};
}
template<typename Value>
requires(!Quantity<Value>) && (!Reference<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, const Value&, Rep>
[[nodiscard]] friend constexpr QuantityOf<inverse(get_quantity_spec(R))> auto operator/(const Value& v,
const quantity& q)
{
return ::mp_units::quantity{v / q.numerical_value_ref_in(get_unit(R)), ::mp_units::one / R};
}

template<auto R, typename Rep, typename Value>
requires(!Quantity<Value>) && (!Reference<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, Rep, const Value&>
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator/(const quantity<R, Rep>& q, const Value& v)
{
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
return quantity{q.numerical_value_ref_in(get_unit(R)) / v, R};
}
template<auto R2, typename Rep2>
requires requires { typename std::common_type_t<quantity, quantity<R2, Rep2>>; } &&
std::equality_comparable<typename std::common_type_t<quantity, quantity<R2, Rep2>>::rep>
[[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity<R2, Rep2>& rhs)
{
using ct = std::common_type_t<quantity, quantity<R2, Rep2>>;
const ct ct_lhs(lhs);
const ct ct_rhs(rhs);
return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit);
}

template<typename Value, auto R, typename Rep>
requires(!Quantity<Value>) && (!Reference<Value>) &&
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, const Value&, Rep>
[[nodiscard]] constexpr QuantityOf<inverse(get_quantity_spec(R))> auto operator/(const Value& v,
const quantity<R, Rep>& q)
{
return quantity{v / q.numerical_value_ref_in(get_unit(R)), ::mp_units::one / R};
}
template<auto R2, typename Rep2>
requires requires { typename std::common_type_t<quantity, quantity<R2, Rep2>>; } &&
std::three_way_comparable<typename std::common_type_t<quantity, quantity<R2, Rep2>>::rep>
[[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity<R2, Rep2>& rhs)
{
using ct = std::common_type_t<quantity, quantity<R2, Rep2>>;
const ct ct_lhs(lhs);
const ct ct_rhs(rhs);
return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit);
}
};

template<auto R1, typename Rep1, auto R2, typename Rep2>
requires requires { typename std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>; } &&
std::equality_comparable<typename std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>::rep>
[[nodiscard]] constexpr bool operator==(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>;
const ct ct_lhs(lhs);
const ct ct_rhs(rhs);
return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit);
}
// CTAD
template<typename Value, Reference R>
requires RepresentationOf<Value, get_quantity_spec(R{}).character>
quantity(Value v, R) -> quantity<R{}, Value>;

template<auto R1, typename Rep1, auto R2, typename Rep2>
requires requires { typename std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>; } &&
std::three_way_comparable<typename std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>::rep>
[[nodiscard]] constexpr auto operator<=>(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>;
const ct ct_lhs(lhs);
const ct ct_rhs(rhs);
return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit);
}
template<QuantityLike Q>
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>;

MP_UNITS_EXPORT_END

Expand Down
Loading

0 comments on commit dd52808

Please sign in to comment.