@@ -165,101 +165,120 @@ class cartesian_vector {
165165 return os << ' [' << vec[0 ] << " , " << vec[1 ] << " , " << vec[2 ] << ' ]' ;
166166 }
167167#endif
168+
169+ template <typename U>
170+ requires requires (const T& t, const U& u) { t + u; }
171+ [[nodiscard]] friend constexpr auto operator +(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
172+ {
173+ using CT = std::common_type_t <T, U>;
174+ return ::mp_units::cartesian_vector<CT>{static_cast <CT>(lhs._coordinates_ [0 ]) + static_cast <CT>(rhs[0 ]),
175+ static_cast <CT>(lhs._coordinates_ [1 ]) + static_cast <CT>(rhs[1 ]),
176+ static_cast <CT>(lhs._coordinates_ [2 ]) + static_cast <CT>(rhs[2 ])};
177+ }
178+
179+ template <typename U>
180+ requires requires (const T& t, const U& u) { t - u; }
181+ [[nodiscard]] friend constexpr auto operator -(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
182+ {
183+ using CT = std::common_type_t <T, U>;
184+ return ::mp_units::cartesian_vector<CT>{static_cast <CT>(lhs._coordinates_ [0 ]) - static_cast <CT>(rhs[0 ]),
185+ static_cast <CT>(lhs._coordinates_ [1 ]) - static_cast <CT>(rhs[1 ]),
186+ static_cast <CT>(lhs._coordinates_ [2 ]) - static_cast <CT>(rhs[2 ])};
187+ }
188+
189+
190+ template <typename U>
191+ requires (!treat_as_floating_point<T> && !treat_as_floating_point<U> && requires (const T& t, const U& u) { t % u; })
192+ [[nodiscard]] friend constexpr auto operator %(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
193+ {
194+ using CT = std::common_type_t <T, U>;
195+ return ::mp_units::cartesian_vector<CT>{static_cast <CT>(lhs._coordinates_ [0 ] % rhs[0 ]),
196+ static_cast <CT>(lhs._coordinates_ [1 ] % rhs[1 ]),
197+ static_cast <CT>(lhs._coordinates_ [2 ] % rhs[2 ])};
198+ }
199+
200+
201+ template <typename S>
202+ requires requires (const T& t, const S& s) { t * s; }
203+ [[nodiscard]] friend constexpr auto operator *(const cartesian_vector<T>& vector, const S& scalar)
204+ {
205+ using CT = std::common_type_t <T, S>;
206+ return ::mp_units::cartesian_vector<CT>{static_cast <CT>(vector._coordinates_ [0 ]) * static_cast <CT>(scalar),
207+ static_cast <CT>(vector._coordinates_ [1 ]) * static_cast <CT>(scalar),
208+ static_cast <CT>(vector._coordinates_ [2 ]) * static_cast <CT>(scalar)};
209+ }
210+
211+
212+ template <typename S>
213+ requires requires (const S& s, const T& t) { s * t; }
214+ [[nodiscard]] friend constexpr auto operator *(const S& scalar, const cartesian_vector<T>& vector)
215+ {
216+ return vector * scalar;
217+ }
218+
219+
220+ template <typename S>
221+ requires requires (const T& t, const S& s) { t / s; }
222+ [[nodiscard]] friend constexpr auto operator /(const cartesian_vector<T>& vector, const S& scalar)
223+ {
224+ using CT = std::common_type_t <T, S>;
225+ return ::mp_units::cartesian_vector<CT>{static_cast <CT>(vector._coordinates_ [0 ]) / static_cast <CT>(scalar),
226+ static_cast <CT>(vector._coordinates_ [1 ]) / static_cast <CT>(scalar),
227+ static_cast <CT>(vector._coordinates_ [2 ]) / static_cast <CT>(scalar)};
228+ }
229+
230+
231+ template <typename U>
232+ requires std::equality_comparable_with<T, U>
233+ [[nodiscard]] friend constexpr bool operator ==(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
234+ {
235+ return lhs._coordinates_ [0 ] == rhs[0 ] && lhs._coordinates_ [1 ] == rhs[1 ] && lhs._coordinates_ [2 ] == rhs[2 ];
236+ }
237+
238+
239+ template <typename U>
240+ requires requires (const T& t, const U& u, decltype (t * u) v) {
241+ t * u;
242+ v + v;
243+ }
244+ [[nodiscard]] friend constexpr auto scalar_product (const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
245+ {
246+ return lhs._coordinates_ [0 ] * rhs[0 ] + lhs._coordinates_ [1 ] * rhs[1 ] + lhs._coordinates_ [2 ] * rhs[2 ];
247+ }
248+
249+
250+ template <typename U>
251+ requires requires (const T& t, const U& u, decltype (t * u) v) {
252+ t * u;
253+ v - v;
254+ }
255+ [[nodiscard]] friend constexpr auto vector_product (const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
256+ {
257+ using CT = std::common_type_t <T, U>;
258+ return ::mp_units::cartesian_vector<CT>{static_cast <CT>(lhs._coordinates_ [1 ]) * static_cast <CT>(rhs[2 ]) -
259+ static_cast <CT>(lhs._coordinates_ [2 ]) * static_cast <CT>(rhs[1 ]),
260+ static_cast <CT>(lhs._coordinates_ [2 ]) * static_cast <CT>(rhs[0 ]) -
261+ static_cast <CT>(lhs._coordinates_ [0 ]) * static_cast <CT>(rhs[2 ]),
262+ static_cast <CT>(lhs._coordinates_ [0 ]) * static_cast <CT>(rhs[1 ]) -
263+ static_cast <CT>(lhs._coordinates_ [1 ]) * static_cast <CT>(rhs[0 ])};
264+ }
168265};
169266
267+
170268template <typename Arg, typename ... Args>
171269 requires (sizeof ...(Args) <= 2 ) && requires { typename std::common_type_t <Arg, Args...>; }
172270cartesian_vector (Arg, Args...) -> cartesian_vector<std::common_type_t <Arg, Args...>>;
173271
174- template <typename T, typename U>
175- requires requires (const T& t, const U& u) { t + u; }
176- [[nodiscard]] constexpr auto operator +(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
177- {
178- return ::mp_units::cartesian_vector{lhs._coordinates_ [0 ] + rhs._coordinates_ [0 ],
179- lhs._coordinates_ [1 ] + rhs._coordinates_ [1 ],
180- lhs._coordinates_ [2 ] + rhs._coordinates_ [2 ]};
181- }
182-
183- template <typename T, typename U>
184- requires requires (const T& t, const U& u) { t - u; }
185- [[nodiscard]] constexpr auto operator -(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
186- {
187- return ::mp_units::cartesian_vector{lhs._coordinates_ [0 ] - rhs._coordinates_ [0 ],
188- lhs._coordinates_ [1 ] - rhs._coordinates_ [1 ],
189- lhs._coordinates_ [2 ] - rhs._coordinates_ [2 ]};
190- }
191-
192- template <typename T, typename U>
193- requires (!treat_as_floating_point<T> && !treat_as_floating_point<U> && requires (const T& t, const U& u) { t % u; })
194- [[nodiscard]] constexpr auto operator %(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
195- {
196- using CT = std::common_type_t <T, U>;
197- return ::mp_units::cartesian_vector<CT>{static_cast <CT>(lhs._coordinates_ [0 ] % rhs._coordinates_ [0 ]),
198- static_cast <CT>(lhs._coordinates_ [1 ] % rhs._coordinates_ [1 ]),
199- static_cast <CT>(lhs._coordinates_ [2 ] % rhs._coordinates_ [2 ])};
200- }
201-
202- template <typename T, typename S>
203- requires requires (const T& t, const S& s) { t * s; }
204- [[nodiscard]] constexpr auto operator *(const cartesian_vector<T>& vector, const S& scalar)
205- {
206- return ::mp_units::cartesian_vector{vector._coordinates_ [0 ] * scalar, vector._coordinates_ [1 ] * scalar,
207- vector._coordinates_ [2 ] * scalar};
208- }
209-
210- template <typename S, typename U>
211- requires requires (const S& s, const U& u) { s * u; }
212- [[nodiscard]] constexpr auto operator *(const S& scalar, const cartesian_vector<U>& vector)
213- {
214- return vector * scalar;
215- }
216-
217- template <typename T, typename S>
218- requires requires (const T& t, const S& s) { t / s; }
219- [[nodiscard]] constexpr auto operator /(const cartesian_vector<T>& vector, const S& scalar)
220- {
221- return ::mp_units::cartesian_vector{vector._coordinates_ [0 ] / scalar, vector._coordinates_ [1 ] / scalar,
222- vector._coordinates_ [2 ] / scalar};
223- }
224-
225- template <typename T, std::equality_comparable_with<T> U>
226- [[nodiscard]] constexpr bool operator ==(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
227- {
228- return lhs._coordinates_ [0 ] == rhs._coordinates_ [0 ] && lhs._coordinates_ [1 ] == rhs._coordinates_ [1 ] &&
229- lhs._coordinates_ [2 ] == rhs._coordinates_ [2 ];
230- }
231-
232- template <typename T, typename U>
233- requires requires (const T& t, const U& u, decltype (t * u) v) {
234- t * u;
235- v + v;
236- }
237- [[nodiscard]] constexpr auto scalar_product (const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
238- {
239- return lhs._coordinates_ [0 ] * rhs._coordinates_ [0 ] + lhs._coordinates_ [1 ] * rhs._coordinates_ [1 ] +
240- lhs._coordinates_ [2 ] * rhs._coordinates_ [2 ];
241- }
242-
243- template <typename T, typename U>
244- requires requires (const T& t, const U& u, decltype (t * u) v) {
245- t * u;
246- v - v;
247- }
248- [[nodiscard]] constexpr auto vector_product (const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
249- {
250- return ::mp_units::cartesian_vector{
251- lhs._coordinates_ [1 ] * rhs._coordinates_ [2 ] - lhs._coordinates_ [2 ] * rhs._coordinates_ [1 ],
252- lhs._coordinates_ [2 ] * rhs._coordinates_ [0 ] - lhs._coordinates_ [0 ] * rhs._coordinates_ [2 ],
253- lhs._coordinates_ [0 ] * rhs._coordinates_ [1 ] - lhs._coordinates_ [1 ] * rhs._coordinates_ [0 ]};
254- }
255272
256273template <class T >
257274inline constexpr bool treat_as_floating_point<cartesian_vector<T>> = treat_as_floating_point<T>;
258275
259276template <class S , class T >
260277inline constexpr bool is_value_preserving<S, cartesian_vector<T>> = is_value_preserving<S, T>;
278+
261279} // namespace mp_units
262280
281+
263282namespace std {
264283template <class T , class U >
265284struct common_type <mp_units::cartesian_vector<T>, mp_units::cartesian_vector<U>> {
@@ -278,7 +297,6 @@ struct common_type<U, mp_units::cartesian_vector<T>> {
278297} // namespace std
279298
280299#if MP_UNITS_HOSTED
281- // TODO use parse and use formatter for the underlying type
282300template <typename T, typename Char>
283301struct MP_UNITS_STD_FMT ::formatter<mp_units::cartesian_vector<T>, Char> :
284302 formatter<std::basic_string_view<Char>, Char> {
0 commit comments