diff --git a/src/core/include/mp-units/framework/customization_points.h b/src/core/include/mp-units/framework/customization_points.h index 29dcda6a..36401d7d 100644 --- a/src/core/include/mp-units/framework/customization_points.h +++ b/src/core/include/mp-units/framework/customization_points.h @@ -105,6 +105,112 @@ constexpr bool is_vector = false; template constexpr bool is_tensor = false; +MP_UNITS_EXPORT_END + +namespace detail::inline norm_impl { + +void norm() = delete; // poison pill + +struct norm_t { + template + [[nodiscard]] constexpr auto operator()(const T& vec) const + { + if constexpr (requires { vec.norm(); }) + return vec.norm(); + else if constexpr (requires { norm(vec); }) + return norm(vec); + else if constexpr (requires { vec.magnitude(); }) + return vec.magnitude(); + else if constexpr (requires { magnitude(vec); }) + return magnitude(vec); + // TODO Is it a good idea to enable fundamental types to represent vector quantities? + // else if constexpr (is_scalar) + // return std::abs(vec); + } +}; + +} // namespace detail::inline norm_impl + +inline namespace cpo { + +MP_UNITS_EXPORT inline constexpr ::mp_units::detail::norm_impl::norm_t norm; + +} + +namespace detail::inline real_impl { + +void real() = delete; // poison pill + +struct real_t { + template + [[nodiscard]] constexpr auto operator()(const T& clx) const + { + if constexpr (requires { clx.real(); }) + return clx.real(); + else if constexpr (requires { real(clx); }) + return real(clx); + } +}; + +} // namespace detail::inline real_impl + +inline namespace cpo { + +MP_UNITS_EXPORT inline constexpr ::mp_units::detail::real_impl::real_t real; + +} + +namespace detail::inline imag_impl { + +void imag() = delete; // poison pill + +struct imag_t { + template + [[nodiscard]] constexpr auto operator()(const T& clx) const + { + if constexpr (requires { clx.imag(); }) + return clx.imag(); + else if constexpr (requires { imag(clx); }) + return imag(clx); + } +}; + +} // namespace detail::inline imag_impl + +inline namespace cpo { + +MP_UNITS_EXPORT inline constexpr ::mp_units::detail::imag_impl::imag_t imag; + +} + +namespace detail::inline modulus_impl { + +void modulus() = delete; // poison pill + +struct modulus_t { + template + [[nodiscard]] constexpr auto operator()(const T& clx) const + { + if constexpr (requires { clx.modulus(); }) + return clx.modulus(); + else if constexpr (requires { modulus(clx); }) + return modulus(clx); + // `std` made a precedence of using `abs` for modulo on `std::complex` + else if constexpr (requires { abs(clx); }) + return abs(clx); + } +}; + +} // namespace detail::inline modulus_impl + +inline namespace cpo { + +MP_UNITS_EXPORT inline constexpr ::mp_units::detail::modulus_impl::modulus_t modulus; + +} + +MP_UNITS_EXPORT_BEGIN + /** * @brief A type trait that defines zero, one, min, and max for a representation type * diff --git a/src/core/include/mp-units/framework/representation_concepts.h b/src/core/include/mp-units/framework/representation_concepts.h index 8be28d05..66a6db2f 100644 --- a/src/core/include/mp-units/framework/representation_concepts.h +++ b/src/core/include/mp-units/framework/representation_concepts.h @@ -118,11 +118,9 @@ concept ComplexRepresentation = Complex && WeaklyRegular && requires(T a, { a - b } -> Complex; { a* b } -> Complex; { a / b } -> Complex; - { real(a) } -> Scalar; - { imag(a) } -> Scalar; - { abs(a) } -> Scalar; - { arg(a) } -> Scalar; - { conj(a) } -> Complex; + { ::mp_units::real(a) } -> Scalar; + { ::mp_units::imag(a) } -> Scalar; + { ::mp_units::modulus(a) } -> Scalar; }; // TODO how to check for a complex(Scalar, Scalar) -> Complex? @@ -138,8 +136,8 @@ concept VectorRepresentation = Vector && WeaklyRegular && requires(T a, T { -a } -> Vector; { a + b } -> Vector; { a - b } -> Vector; + { ::mp_units::norm(a) } -> Scalar; // TBD - // { norm(a) } -> Scalar; // { zero_vector() } -> Vector; // { unit_vector(a) } -> Vector; // { scalar_product(a, b) } -> Scalar;