/*************************************************************************** * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_COMPLEX_HPP #define XTL_COMPLEX_HPP #if !defined(_MSC_VER) #include using std::copysign; #endif #include #include #include #include #include #include #include #ifdef __CLING__ #include #endif #include "xclosure.hpp" #include "xtl_config.hpp" #include "xtype_traits.hpp" namespace xtl { template class xcomplex; /************** * is_complex * **************/ namespace detail { template struct is_complex : std::false_type { }; template struct is_complex> : std::true_type { }; } template struct is_complex { static constexpr bool value = detail::is_complex>::value; }; /*************** * is_xcomplex * ***************/ namespace detail { template struct is_xcomplex : std::false_type { }; template struct is_xcomplex> : std::true_type { }; } template struct is_xcomplex { static constexpr bool value = detail::is_xcomplex>::value; }; /****************** * is_gen_complex * ******************/ template using is_gen_complex = disjunction>, is_xcomplex>>; /**************************** * enable / disable complex * ****************************/ template using disable_xcomplex = std::enable_if_t::value, R>; template using enable_xcomplex = std::enable_if_t::value, R>; /***************** * enable_scalar * *****************/ template using enable_scalar = std::enable_if_t::value, R>; /******************* * common_xcomplex * *******************/ template struct common_xcomplex { using type = xcomplex, std::common_type_t, ieee1 || ieee2>; }; template using common_xcomplex_t = typename common_xcomplex::type; /********************** * temporary_xcomplex * **********************/ template struct temporary_xcomplex { using type = xcomplex, std::decay_t, ieee>; }; template using temporary_xcomplex_t = typename temporary_xcomplex::type; /************ * xcomplex * ************/ template class xcomplex { public: static_assert(std::is_same, std::decay_t>::value, "closure types must have the same value type"); using value_type = std::common_type_t; using self_type = xcomplex; using temporary_type = temporary_xcomplex_t; using real_reference = std::add_lvalue_reference_t; using real_const_reference = std::add_lvalue_reference_t>; using real_rvalue_reference = std::conditional_t::value, apply_cv_t&, value_type>; using real_rvalue_const_reference = std::conditional_t::value, const value_type&, value_type>; using imag_reference = std::add_lvalue_reference_t; using imag_const_reference = std::add_lvalue_reference_t>; using imag_rvalue_reference = std::conditional_t::value, apply_cv_t&, value_type>; using imag_rvalue_const_reference = std::conditional_t::value, const value_type&, value_type>; constexpr xcomplex() noexcept : m_real(), m_imag() { } template >, std::is_constructible, std::is_convertible >::value, bool > = true> constexpr xcomplex(OCTR&& re) noexcept : m_real(std::forward(re)), m_imag() { } template >, std::is_constructible, negation> >::value, bool > = true> explicit constexpr xcomplex(OCTR&& re) noexcept : m_real(std::forward(re)), m_imag() { } template explicit constexpr xcomplex(OCTR&& re, OCTI&& im) noexcept : m_real(std::forward(re)), m_imag(std::forward(im)) { } template explicit constexpr xcomplex(const xcomplex& rhs) noexcept : m_real(rhs.real()), m_imag(rhs.imag()) { } template explicit constexpr xcomplex(xcomplex&& rhs) noexcept : m_real(std::move(rhs).real()), m_imag(std::move(rhs).imag()) { } template constexpr xcomplex(const std::complex& rhs) noexcept : m_real(rhs.real()), m_imag(rhs.imag()) { } template constexpr xcomplex(std::complex&& rhs) noexcept : m_real(std::move(rhs).real()), m_imag(std::move(rhs).imag()) { } template disable_xcomplex operator=(OCTR&& rhs) noexcept; template self_type& operator=(const xcomplex& rhs) noexcept; template self_type& operator=(xcomplex&& rhs) noexcept; operator std::complex>() const noexcept; template self_type& operator+=(const xcomplex& rhs) noexcept; template self_type& operator-=(const xcomplex& rhs) noexcept; template self_type& operator*=(const xcomplex& rhs) noexcept; template self_type& operator/=(const xcomplex& rhs) noexcept; template disable_xcomplex operator+=(const T& rhs) noexcept; template disable_xcomplex operator-=(const T& rhs) noexcept; template disable_xcomplex operator*=(const T& rhs) noexcept; template disable_xcomplex operator/=(const T& rhs) noexcept; real_reference real() & noexcept; real_rvalue_reference real() && noexcept; constexpr real_const_reference real() const & noexcept; constexpr real_rvalue_const_reference real() const && noexcept; imag_reference imag() & noexcept; imag_rvalue_reference imag() && noexcept; constexpr imag_const_reference imag() const & noexcept; constexpr imag_rvalue_const_reference imag() const && noexcept; xclosure_pointer operator&() & noexcept; xclosure_pointer operator&() const & noexcept; xclosure_pointer operator&() && noexcept; private: CTR m_real; CTI m_imag; }; /********************** * xcomplex operators * **********************/ template bool operator==(const xcomplex& lhs, const xcomplex& rhs) noexcept; template bool operator!=(const xcomplex& lhs, const xcomplex& rhs) noexcept; template std::basic_ostream& operator<<(std::basic_ostream& out, const xcomplex& c) noexcept; template temporary_xcomplex_t operator+(const xcomplex& rhs) noexcept; template temporary_xcomplex_t operator-(const xcomplex& rhs) noexcept; template common_xcomplex_t operator+(const xcomplex& lhs, const xcomplex& rhs) noexcept; template enable_scalar> operator+(const xcomplex& lhs, const T& rhs) noexcept; template enable_scalar> operator+(const T& lhs, const xcomplex& rhs) noexcept; template common_xcomplex_t operator-(const xcomplex& lhs, const xcomplex& rhs) noexcept; template enable_scalar> operator-(const xcomplex& lhs, const T& rhs) noexcept; template enable_scalar> operator-(const T& lhs, const xcomplex& rhs) noexcept; template common_xcomplex_t operator*(const xcomplex& lhs, const xcomplex& rhs) noexcept; template enable_scalar> operator*(const xcomplex& lhs, const T& rhs) noexcept; template enable_scalar> operator*(const T& lhs, const xcomplex& rhs) noexcept; template common_xcomplex_t operator/(const xcomplex& lhs, const xcomplex& rhs) noexcept; template enable_scalar> operator/(const xcomplex& lhs, const T& rhs) noexcept; template enable_scalar> operator/(const T& lhs, const xcomplex& rhs) noexcept; /***************** * real and imag * *****************/ template decltype(auto) real(E&& e) noexcept; template decltype(auto) imag(E&& e) noexcept; /*************************** * xcomplex free functions * ***************************/ template typename xcomplex::value_type abs(const xcomplex& rhs); template typename xcomplex::value_type arg(const xcomplex& rhs); template typename xcomplex::value_type norm(const xcomplex& rhs); template temporary_xcomplex_t conj(const xcomplex& rhs); template temporary_xcomplex_t proj(const xcomplex& rhs); /********************************** * xcomplex exponential functions * **********************************/ template temporary_xcomplex_t exp(const xcomplex& rhs); template temporary_xcomplex_t log(const xcomplex& rhs); template temporary_xcomplex_t log10(const xcomplex& rhs); /**************************** * xcomplex power functions * ****************************/ template common_xcomplex_t pow(const xcomplex& x, const xcomplex& y); template enable_scalar> pow(const xcomplex& x, const T& y); template enable_scalar> pow(const T& x, const xcomplex& y); template temporary_xcomplex_t sqrt(const xcomplex& x); /************************************ * xcomplex trigonometric functions * ************************************/ template temporary_xcomplex_t sin(const xcomplex& x); template temporary_xcomplex_t cos(const xcomplex& x); template temporary_xcomplex_t tan(const xcomplex& x); template temporary_xcomplex_t asin(const xcomplex& x); template temporary_xcomplex_t acos(const xcomplex& x); template temporary_xcomplex_t atan(const xcomplex& x); /********************************* * xcomplex hyperbolic functions * *********************************/ template temporary_xcomplex_t sinh(const xcomplex& x); template temporary_xcomplex_t cosh(const xcomplex& x); template temporary_xcomplex_t tanh(const xcomplex& x); template temporary_xcomplex_t asinh(const xcomplex& x); template temporary_xcomplex_t acosh(const xcomplex& x); template temporary_xcomplex_t atanh(const xcomplex& x); /*************************** * xcomplex implementation * ***************************/ template template inline auto xcomplex::operator=(OCTR&& rhs) noexcept -> disable_xcomplex { m_real = std::forward(rhs); m_imag = std::decay_t(); return *this; } template template inline auto xcomplex::operator=(const xcomplex& rhs) noexcept -> self_type& { m_real = rhs.m_real; m_imag = rhs.m_imag; return *this; } template template inline auto xcomplex::operator=(xcomplex&& rhs) noexcept -> self_type& { m_real = std::move(rhs.m_real); m_imag = std::move(rhs.m_imag); return *this; } template inline xcomplex::operator std::complex>() const noexcept { return std::complex>(m_real, m_imag); } template template inline auto xcomplex::operator+=(const xcomplex& rhs) noexcept -> self_type& { m_real += rhs.m_real; m_imag += rhs.m_imag; return *this; } template template inline auto xcomplex::operator-=(const xcomplex& rhs) noexcept -> self_type& { m_real -= rhs.m_real; m_imag -= rhs.m_imag; return *this; } namespace detail { template struct xcomplex_multiplier { template static auto mul(const xcomplex& lhs, const xcomplex& rhs) { using return_type = temporary_xcomplex_t; using value_type = typename return_type::value_type; value_type a = lhs.real(); value_type b = lhs.imag(); value_type c = rhs.real(); value_type d = rhs.imag(); return return_type(a*c - b*d, a*d + b*c); } template static auto div(const xcomplex& lhs, const xcomplex& rhs) { using return_type = temporary_xcomplex_t; using value_type = typename return_type::value_type; value_type a = lhs.real(); value_type b = lhs.imag(); value_type c = rhs.real(); value_type d = rhs.imag(); value_type e = c*c + d*d; return return_type((c*a + d*b) / e, (c*b - d*a) / e); } }; template <> struct xcomplex_multiplier { template static auto mul(const xcomplex& lhs, const xcomplex& rhs) { using return_type = temporary_xcomplex_t; using value_type = typename return_type::value_type; value_type a = lhs.real(); value_type b = lhs.imag(); value_type c = rhs.real(); value_type d = rhs.imag(); value_type ac = a * c; value_type bd = b * d; value_type ad = a * d; value_type bc = b * c; value_type x = ac - bd; value_type y = ad + bc; if (std::isnan(x) && std::isnan(y)) { bool recalc = false; if (std::isinf(a) || std::isinf(b)) { a = copysign(std::isinf(a) ? value_type(1) : value_type(0), a); b = copysign(std::isinf(b) ? value_type(1) : value_type(0), b); if (std::isnan(c)) { c = copysign(value_type(0), c); } if (std::isnan(d)) { d = copysign(value_type(0), d); } recalc = true; } if (std::isinf(c) || std::isinf(d)) { c = copysign(std::isinf(c) ? value_type(1) : value_type(0), c); d = copysign(std::isinf(c) ? value_type(1) : value_type(0), d); if (std::isnan(a)) { a = copysign(value_type(0), a); } if (std::isnan(b)) { b = copysign(value_type(0), b); } recalc = true; } if (!recalc && (std::isinf(ac) || std::isinf(bd) || std::isinf(ad) || std::isinf(bc))) { if (std::isnan(a)) { a = copysign(value_type(0), a); } if (std::isnan(b)) { b = copysign(value_type(0), b); } if (std::isnan(c)) { c = copysign(value_type(0), c); } if (std::isnan(d)) { d = copysign(value_type(0), d); } recalc = true; } if (recalc) { x = std::numeric_limits::infinity() * (a * c - b * d); y = std::numeric_limits::infinity() * (a * d + b * c); } } return return_type(x, y); } template static auto div(const xcomplex& lhs, const xcomplex& rhs) { using return_type = temporary_xcomplex_t; using value_type = typename return_type::value_type; value_type a = lhs.real(); value_type b = lhs.imag(); value_type c = rhs.real(); value_type d = rhs.imag(); value_type logbw = std::logb(std::fmax(std::fabs(c), std::fabs(d))); int ilogbw = 0; if (std::isfinite(logbw)) { ilogbw = static_cast(logbw); c = std::scalbn(c, -ilogbw); d = std::scalbn(d, -ilogbw); } value_type denom = c*c + d*d; value_type x = std::scalbn((a*c + b*d) / denom, -ilogbw); value_type y = std::scalbn((b*c - a*d) / denom, -ilogbw); if (std::isnan(x) && std::isnan(y)) { if ((denom == value_type(0)) && (!std::isnan(a) || !std::isnan(b))) { x = copysign(std::numeric_limits::infinity(), c) * a; y = copysign(std::numeric_limits::infinity(), c) * b; } else if ((std::isinf(a) || std::isinf(b)) && std::isfinite(c) && std::isfinite(d)) { a = copysign(std::isinf(a) ? value_type(1) : value_type(0), a); b = copysign(std::isinf(b) ? value_type(1) : value_type(0), b); x = std::numeric_limits::infinity() * (a*c + b*d); y = std::numeric_limits::infinity() * (b*c - a*d); } else if (std::isinf(logbw) && logbw > value_type(0) && std::isfinite(a) && std::isfinite(b)) { c = copysign(std::isinf(c) ? value_type(1) : value_type(0), c); d = copysign(std::isinf(d) ? value_type(1) : value_type(0), d); x = value_type(0) * (a*c + b*d); y = value_type(0) * (b*c - a*d); } } return std::complex(x, y); } }; } template template inline auto xcomplex::operator*=(const xcomplex& rhs) noexcept -> self_type& { *this = detail::xcomplex_multiplier::mul(*this, rhs); return *this; } template template inline auto xcomplex::operator/=(const xcomplex& rhs) noexcept -> self_type& { *this = detail::xcomplex_multiplier::div(*this, rhs); return *this; } template template inline auto xcomplex::operator+=(const T& rhs) noexcept -> disable_xcomplex { m_real += rhs; return *this; } template template inline auto xcomplex::operator-=(const T& rhs) noexcept -> disable_xcomplex { m_real -= rhs; return *this; } template template inline auto xcomplex::operator*=(const T& rhs) noexcept -> disable_xcomplex { m_real *= rhs; m_imag *= rhs; return *this; } template template inline auto xcomplex::operator/=(const T& rhs) noexcept -> disable_xcomplex { m_real /= rhs; m_imag /= rhs; return *this; } template auto xcomplex::real() & noexcept -> real_reference { return m_real; } template auto xcomplex::real() && noexcept -> real_rvalue_reference { return m_real; } template constexpr auto xcomplex::real() const & noexcept -> real_const_reference { return m_real; } template constexpr auto xcomplex::real() const && noexcept -> real_rvalue_const_reference { return m_real; } template auto xcomplex::imag() & noexcept -> imag_reference { return m_imag; } template auto xcomplex::imag() && noexcept -> imag_rvalue_reference { return m_imag; } template constexpr auto xcomplex::imag() const & noexcept -> imag_const_reference { return m_imag; } template constexpr auto xcomplex::imag() const && noexcept -> imag_rvalue_const_reference { return m_imag; } template inline auto xcomplex::operator&() & noexcept -> xclosure_pointer { return xclosure_pointer(*this); } template inline auto xcomplex::operator&() const & noexcept -> xclosure_pointer { return xclosure_pointer(*this); } template inline auto xcomplex::operator&() && noexcept -> xclosure_pointer { return xclosure_pointer(std::move(*this)); } /************************************* * xcomplex operators implementation * *************************************/ template inline bool operator==(const xcomplex& lhs, const xcomplex& rhs) noexcept { return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); } template inline bool operator!=(const xcomplex& lhs, const xcomplex& rhs) noexcept { return !(lhs == rhs); } template inline std::basic_ostream& operator<<(std::basic_ostream& out, const xcomplex& c) noexcept { out << "(" << c.real() << "," << c.imag() << ")"; return out; } #ifdef __CLING__ template nlohmann::json mime_bundle_repr(const xcomplex& c) { auto bundle = nlohmann::json::object(); std::stringstream tmp; tmp << c; bundle["text/plain"] = tmp.str(); return bundle; } #endif template inline temporary_xcomplex_t operator+(const xcomplex& rhs) noexcept { return rhs; } template inline temporary_xcomplex_t operator-(const xcomplex& rhs) noexcept { return temporary_xcomplex_t(-rhs.real(), -rhs.imag()); } template inline common_xcomplex_t operator+(const xcomplex& lhs, const xcomplex& rhs) noexcept { common_xcomplex_t res(lhs); res += rhs; return res; } template inline enable_scalar> operator+(const xcomplex& lhs, const T& rhs) noexcept { temporary_xcomplex_t res(lhs); res += rhs; return res; } template inline enable_scalar> operator+(const T& lhs, const xcomplex& rhs) noexcept { temporary_xcomplex_t res(lhs); res += rhs; return res; } template inline common_xcomplex_t operator-(const xcomplex& lhs, const xcomplex& rhs) noexcept { common_xcomplex_t res(lhs); res -= rhs; return res; } template inline enable_scalar> operator-(const xcomplex& lhs, const T& rhs) noexcept { temporary_xcomplex_t res(lhs); res -= rhs; return res; } template inline enable_scalar> operator-(const T& lhs, const xcomplex& rhs) noexcept { temporary_xcomplex_t res(lhs); res -= rhs; return res; } template inline common_xcomplex_t operator*(const xcomplex& lhs, const xcomplex& rhs) noexcept { common_xcomplex_t res(lhs); res *= rhs; return res; } template inline enable_scalar> operator*(const xcomplex& lhs, const T& rhs) noexcept { temporary_xcomplex_t res(lhs); res *= rhs; return res; } template inline enable_scalar> operator*(const T& lhs, const xcomplex& rhs) noexcept { temporary_xcomplex_t res(lhs); res *= rhs; return res; } template inline common_xcomplex_t operator/(const xcomplex& lhs, const xcomplex& rhs) noexcept { common_xcomplex_t res(lhs); res /= rhs; return res; } template inline enable_scalar> operator/(const xcomplex& lhs, const T& rhs) noexcept { temporary_xcomplex_t res(lhs); res /= rhs; return res; } template inline enable_scalar> operator/(const T& lhs, const xcomplex& rhs) noexcept { temporary_xcomplex_t res(lhs); res /= rhs; return res; } /*************************** * xcomplex free functions * ***************************/ template inline typename xcomplex::value_type abs(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::abs(std::complex(rhs)); } template inline typename xcomplex::value_type arg(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::arg(std::complex(rhs)); } template inline typename xcomplex::value_type norm(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::norm(std::complex(rhs)); } template inline temporary_xcomplex_t conj(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::conj(std::complex(rhs)); } template inline temporary_xcomplex_t proj(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::proj(std::complex(rhs)); } /************************************************* * xcomplex exponential functions implementation * *************************************************/ template inline temporary_xcomplex_t exp(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::exp(std::complex(rhs)); } template inline temporary_xcomplex_t log(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::log(std::complex(rhs)); } template inline temporary_xcomplex_t log10(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::log10(std::complex(rhs)); } /******************************************* * xcomplex power functions implementation * *******************************************/ template inline common_xcomplex_t pow(const xcomplex& x, const xcomplex& y) { using value_type1 = typename xcomplex::value_type; using value_type2 = typename xcomplex::value_type; return std::pow(std::complex(x), std::complex(y)); } template inline enable_scalar> pow(const xcomplex& x, const T& y) { using value_type = typename xcomplex::value_type; return std::pow(std::complex(x), y); } template inline enable_scalar> pow(const T& x, const xcomplex& y) { using value_type = typename xcomplex::value_type; return std::pow(x, std::complex(y)); } template inline temporary_xcomplex_t sqrt(const xcomplex& x) { using value_type = typename xcomplex::value_type; return std::sqrt(std::complex(x)); } /*************************************************** * xcomplex trigonometric functions implementation * ***************************************************/ template inline temporary_xcomplex_t sin(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::sin(std::complex(x)); } template inline temporary_xcomplex_t cos(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::cos(std::complex(x)); } template inline temporary_xcomplex_t tan(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::tan(std::complex(x)); } template inline temporary_xcomplex_t asin(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::asin(std::complex(x)); } template inline temporary_xcomplex_t acos(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::acos(std::complex(x)); } template inline temporary_xcomplex_t atan(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::atan(std::complex(x)); } /************************************************ * xcomplex hyperbolic functions implementation * ************************************************/ template inline temporary_xcomplex_t sinh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::sinh(std::complex(x)); } template inline temporary_xcomplex_t cosh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::cosh(std::complex(x)); } template inline temporary_xcomplex_t tanh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::tanh(std::complex(x)); } template inline temporary_xcomplex_t asinh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::asinh(std::complex(x)); } template inline temporary_xcomplex_t acosh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::acosh(std::complex(x)); } template inline temporary_xcomplex_t atanh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::atanh(std::complex(x)); } /********************************* * forward_offset implementation * *********************************/ namespace detail { template struct forward_type { using type = apply_cv_t; }; template struct forward_type { using type = apply_cv_t&; }; template using forward_type_t = typename forward_type::type; } template constexpr detail::forward_type_t forward_offset(T&& v) noexcept { using forward_type = detail::forward_type_t; using cv_value_type = std::remove_reference_t; using byte_type = apply_cv_t, char>; return static_cast( *reinterpret_cast( reinterpret_cast(&v) + I ) ); } /********************************************** * forward_real & forward_imag implementation * **********************************************/ // forward_real template auto forward_real(T&& v) -> std::enable_if_t::value, detail::forward_type_t> // real case -> forward { return static_cast>(v); } template auto forward_real(T&& v) -> std::enable_if_t::value, detail::forward_type_t::value_type>> // complex case -> forward the real part { return forward_offset::value_type, 0>(v); } template auto forward_real(T&& v) -> std::enable_if_t::value, decltype(std::forward(v).real())> { return std::forward(v).real(); } // forward_imag template auto forward_imag(T &&) -> std::enable_if_t::value, std::decay_t> // real case -> always return 0 by value { return 0; } template auto forward_imag(T&& v) -> std::enable_if_t::value, detail::forward_type_t::value_type>> // complex case -> forwards the imaginary part { using real_type = typename std::decay_t::value_type; return forward_offset(v); } template auto forward_imag(T&& v) -> std::enable_if_t::value, decltype(std::forward(v).imag())> { return std::forward(v).imag(); } /****************************** * real & imag implementation * ******************************/ template inline decltype(auto) real(E&& e) noexcept { return forward_real(std::forward(e)); } template inline decltype(auto) imag(E&& e) noexcept { return forward_imag(std::forward(e)); } /********************** * complex_value_type * **********************/ template struct complex_value_type { using type = T; }; template struct complex_value_type> { using type = T; }; template struct complex_value_type> { using type = xcomplex; }; template using complex_value_type_t = typename complex_value_type::type; /****************************************************** * operator overloads for complex and closure wrapper * *****************************************************/ template ::value, int> = 0> std::complex operator+(const std::complex& c, const T& t) { std::complex result(c); result += t; return result; } template ::value, int> = 0> std::complex operator+(const T& t, const std::complex& c) { std::complex result(t); result += c; return result; } template ::value, int> = 0> std::complex operator-(const std::complex& c, const T& t) { std::complex result(c); result -= t; return result; } template ::value, int> = 0> std::complex operator-(const T& t, const std::complex& c) { std::complex result(t); result -= c; return result; } template ::value, int> = 0> std::complex operator*(const std::complex& c, const T& t) { std::complex result(c); result *= t; return result; } template ::value, int> = 0> std::complex operator*(const T& t, const std::complex& c) { std::complex result(t); result *= c; return result; } template ::value, int> = 0> std::complex operator/(const std::complex& c, const T& t) { std::complex result(c); result /= t; return result; } template ::value, int> = 0> std::complex operator/(const T& t, const std::complex& c) { std::complex result(t); result /= c; return result; } } #endif