How to avoid the built-in `std :: complex` when providing` T = std :: complex <Q> `?
To solve the polynomial equation, it would be great to create a template for access to any type:
template <class number, int degree> class PolynomialEquation { public: private: array<number, degree+1> myEquation; array<complex<number>, degree> equationResult; }; This allows you to use, for example, double in used for input, and the result is std::complex<double> in โ (we know that from degree 2 or more the solution of the equation usually falls into โ, for example: x ^ 2 + 1).
But the input to the equation can also be a std::complex . In this case, the type myEquation should be complex, but equationResult should NOT be std::complex<complex<T>> , but simply a normal complex number of type T
Questions:
How to make the equationResult type a subtype of std::complex when the equation is supplied with std::complex ?
Is there an equivalent to std::is_floating_point such as std :: is_complex_number?
You can create traits, for example:
template <typename T> struct to_complex { using type = std::complex<T>; }; template <typename T> struct to_complex<std::complex<T>> { using type = std::complex<T>; }; And then
template <class number, int degree> class PolynomialEquation { public: private: array<number, degree+1> myEquation; array<typename to_complex<number>::type, degree> equationResult; }; I don't think there is a trait for checking if a type is a complex number, but it is relatively easy to create (also an alternative implementation of Jarod to_complex ):
#include <type_traits> #include <complex> #include <iostream> template <class T> struct is_complex_number: std::false_type { }; template <class T> struct is_complex_number<std::complex<T>>: std::true_type { }; template <class T> struct to_complex: std::conditional<is_complex_number<T>::value, T, std::complex<T>> { }; int main() { std::cout << is_complex_number<float>::value << std::endl; // output: 0 std::cout << is_complex_number<std::complex<float>>::value << std::endl; // output: 1 typename to_complex<float>::type c; // decltype(c) == complex<float> typename to_complex<std::complex<float>>::type d; // decltype(d) == complex<float> } Here's a single-line version of C ++ 14, alternative to @WF
using Complex = typename std::conditional<std::is_arithmetic<T>::value, std::complex<T>, T>::type; It is assumed that if it is not an arithmetic type, then it must be complex. If you are not careful, you need to make sure that T is either arithmetic (or even a floating point) or complex. You will need to mix this with @WF anwser.
I have a class of polynomials where I potentially needed real coefficients and complex x (as well as real, real and complex, complex). I did is_complex:
/** * Introspection class to detect if a type is std::complex. */ template<typename _Tp> struct is_complex : public std::false_type { }; /** * Introspection class to detect if a type is std::complex. */ template<> template<typename _Tp> struct is_complex<std::complex<_Tp>> : public std::true_type { }; /** * Introspection type to detect if a type is std::complex. */ template<typename _Tp> using is_complex_t = typename is_complex<_Tp>::type; /** * Introspection variable template to detect if a type is std::complex. */ template<typename _Tp> constexpr bool is_complex_v = is_complex<_Tp>::value; In addition, I use tools to extract the scalar type, whether the input is scalar or complex, so I can use numerical constraints, for example:
template<typename Tp> struct num_traits { using __value_type = Tp; }; template<> template<typename Tp> struct num_traits<std::complex<Tp>> { using __value_type = typename std::complex<Tp>::value_type; }; template<typename Tp> using num_traits_t = typename num_traits<Tp>::__value_type; which I could use as follows:
using Val = num_traits_t<Ret>; constexpr auto eps = std::numeric_limits<Val>::epsilon(); and then build convergence tests for both real and complex inputs.