2016-07-28 20 views
6

Für eine Polynomgleichung Löser, wäre es toll, es als Templat jede Art zur Verfügung zu haben:Wie vermeidet man eingebettete `std :: complex` wenn` T = std :: complex <Q> `?

template <class number, int degree> 
class PolynomialEquation 
{ 
public: 

private: 
    array<number, degree+1> myEquation; 
    array<complex<number>, degree> equationResult; 
}; 

Dies ermöglicht zum Beispiel double in r für die Eingabe verwendet werden, und das Ergebnis std::complex<double> sein in ℂ (wir wissen, dass ab Gleichung 2 und mehr Lösung zu Gleichung gewöhnlich in ∞ fällt, Beispiel: x^2 + 1). Die Eingabe in die Gleichung könnte auch eine std::complex sein. In diesem Fall sollte der Typ myEquation komplex sein, aber sollte NICHT ein std::complex<complex<T>> sein, sondern nur eine normale komplexe Zahl vom Typ T.

Fragen:

Wie die Art des equationResult machen der Untertyp von std::complex zu sein, wenn die Gleichung mit std::complex zur Verfügung gestellt?

Gibt es eine std::is_floating_point Entsprechung wie std :: is_complex_number?

Antwort

7

Sie können einen Zug schaffen, wie etwas:

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>; 
}; 

Und dann

template <class number, int degree> 
class PolynomialEquation 
{ 
public: 

private: 
    array<number, degree+1> myEquation; 
    array<typename to_complex<number>::type, degree> equationResult; 
}; 
+1

Wahrscheinlich würde ich es 'poly_root_type_traits' oder so ähnlich nennen -' to_complex' ist ein wenig unklar über die Gründe hinter dieser Sache. –

2

Ich glaube nicht, dass es ein Merkmal für die Überprüfung ist, wenn der Typ eine komplexe Zahl ist es aber sollte relativ einfach zu erstellen sein (auch die alternative Implementierung zu 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> 
} 
+0

Ich kann mir keinen Weg vorstellen, std :: same in einem Einzeiler zu verwenden, oder?Gibt es in type_traits etwas, um zu prüfen, ob T eine Vorlagenvorlage ist und ob es das Format U hat? –

+0

@ Benoît wenn 'V' ein Typ Template-Parameter ist, könnte man die consExpr-Funktion mit zwei Überladungen erstellen:' template consExpr bool is_template_template() {return false; } Vorlage Klasse> constexpr bool is_template_template() {return true; } '. Leider kenne ich den STL-Ansatz dafür nicht ... –

2

Hier ist eine C++ 14 One-Liner-Alternative zu @ W.F.

using Complex = typename std::conditional<std::is_arithmetic<T>::value, std::complex<T>, T>::type; 

Die Annahme ist, dass, wenn es sich nicht um einen arithmetischen Typ handelt, es komplex sein sollte. Wenn Sie gründlich sein wollen, müssen Sie sicherstellen, dass T entweder arithmetisch (oder sogar Fließkomma) oder komplex ist. Sie müssten dies mit @ W.F mischen. anwser.

1

Ich habe eine Polynom-Klasse, wo ich potenziell reelle Koeffizienten und komplexe x (sowie real, real und komplex, komplex) wollte. Ich machte eine 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; 

Auch ich Tools verwenden, um die skalaren Typ zu extrahieren, ob die Eingabe Skalar oder komplex ist, so gibt es numerische Grenzen Einrichtungen zum Beispiel verwenden können:

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; 

, die ich verwenden könnte wie folgt:

using Val = num_traits_t<Ret>; 
    constexpr auto eps = std::numeric_limits<Val>::epsilon(); 

und anschließend Konvergenztests für reale und komplexe Eingaben erstellen.