@@ -47,11 +47,22 @@ import std;
4747#endif
4848#endif
4949
50+ #if MP_UNITS_HOSTED
51+ #ifndef MP_UNITS_STD_FMT
52+ #define MP_UNITS_STD_FMT std
53+ #endif
54+ #endif
55+
5056namespace mp_units {
5157
5258MP_UNITS_EXPORT template <detail::Scalar T>
5359class cartesian_vector ;
5460
61+ template <class X >
62+ struct is_exact_cartesian_vector : std::false_type {};
63+ template <detail::Scalar U>
64+ struct is_exact_cartesian_vector <cartesian_vector<U>> : std::true_type {};
65+
5566MP_UNITS_EXPORT template <detail::Scalar T = double >
5667class cartesian_vector {
5768public:
@@ -128,7 +139,8 @@ class cartesian_vector {
128139 }
129140
130141 template <typename S>
131- requires requires (T& t, const S& s) { t *= s; }
142+ requires detail::Scalar<S> && (!is_exact_cartesian_vector<std::remove_cvref_t <S>>::value) &&
143+ requires (T& t, const S& s) { t *= s; }
132144 constexpr cartesian_vector& operator *=(const S& scalar)
133145 {
134146 _coordinates_[0 ] *= scalar;
@@ -138,7 +150,8 @@ class cartesian_vector {
138150 }
139151
140152 template <typename S>
141- requires requires (T& t, const S& s) { t /= s; }
153+ requires detail::Scalar<S> && (!is_exact_cartesian_vector<std::remove_cvref_t <S>>::value) &&
154+ requires (T& t, const S& s) { t /= s; }
142155 constexpr cartesian_vector& operator /=(const S& scalar)
143156 {
144157 _coordinates_[0 ] /= scalar;
@@ -196,8 +209,10 @@ class cartesian_vector {
196209 static_cast <CT>(lhs._coordinates_ [2 ] % rhs[2 ])};
197210 }
198211
212+
199213 template <typename S>
200- requires requires (const T& t, const S& s) { t * s; }
214+ requires detail::Scalar<S> && (!is_exact_cartesian_vector<std::remove_cvref_t <S>>::value) &&
215+ requires (const T& t, const S& s) { t * s; }
201216 [[nodiscard]] friend constexpr auto operator *(const cartesian_vector<T>& vector, const S& scalar)
202217 {
203218 using CT = std::common_type_t <T, S>;
@@ -207,14 +222,16 @@ class cartesian_vector {
207222 }
208223
209224 template <typename S>
210- requires requires (const S& s, const T& t) { s * t; }
225+ requires detail::Scalar<S> && (!is_exact_cartesian_vector<std::remove_cvref_t <S>>::value) &&
226+ requires (const S& s, const T& t) { s * t; }
211227 [[nodiscard]] friend constexpr auto operator *(const S& scalar, const cartesian_vector<T>& vector)
212228 {
213229 return vector * scalar;
214230 }
215231
216232 template <typename S>
217- requires requires (const T& t, const S& s) { t / s; }
233+ requires detail::Scalar<S> && (!is_exact_cartesian_vector<std::remove_cvref_t <S>>::value) &&
234+ requires (const T& t, const S& s) { t / s; }
218235 [[nodiscard]] friend constexpr auto operator /(const cartesian_vector<T>& vector, const S& scalar)
219236 {
220237 using CT = std::common_type_t <T, S>;
@@ -261,11 +278,6 @@ template<typename Arg, typename... Args>
261278 requires (sizeof ...(Args) <= 2 ) && requires { typename std::common_type_t <Arg, Args...>; }
262279cartesian_vector (Arg, Args...) -> cartesian_vector<std::common_type_t <Arg, Args...>>;
263280
264- // NOTE: We do NOT specialize treat_as_floating_point for cartesian_vector<T>.
265- // Doing so would make the vector attempt to model a "scalar" in mp-units'
266- // concept lattice and triggers recursive constraints.
267-
268- // Keep value-preserving semantics delegated to element type.
269281template <class S , class T >
270282inline constexpr bool is_value_preserving<S, cartesian_vector<T>> = is_value_preserving<S, T>;
271283
0 commit comments