2012-11-22 7 views
5

Betrachten Sie die exponentiell glattere Vorlagenklasse unten. Diese Klasse dient zum exponentiellen Glätten/Filtern sequentieller Daten (siehe Update-Methode). Elemtype könnte ein Vektor sein und Floattype ist normalerweise ein Skalar. Z.B.C++ Überprüfen Sie für geschachtelte typedef eines Vorlageparameters, um seinen skalaren Basistyp zu erhalten

ExponentialSmoother<Eigen::Vector2f, float> x(0.1, Vector2f(0.5, 0.5)); 

In diesem Beispiel wird die zweite Template-Parameter Floattype vermieden werden könnten, weil Eigens Matrix-Klasse eine verschachtelte typedef enthält die skalaren Basistyp zu erhalten:

Vector2f::Scalar 

Es ist auch sinnvoll sowohl Elemtype und Floatype zu instanziiert schwebt, um eindimensionale Daten zu glätten. In diesem Fall könnte der zweite Template-Parameter auch übersprungen werden.

template <class Elemtype, class Floattype> 
class ExponentialSmoother 
{ 
public: 
    // ctor 
    ExponentialSmoother(Floattype alpha, Elemtype& initial_estimate); 

    // getters 
    inline const Elemtype& getValue() const {return estimate_;} 
    inline const Floattype getAlpha() const {return alpha_;} 

    const Elemtype& update(const Elemtype& curr) 
    { 
     estimate_ = (alpha_ * curr) + (((Floattype)1-alpha) * estimate_); 
     return estimate_; 
    } 

private: 
    Elemtype estimate_; 
    Floattype alpha_; // smoothing factor within [0,1] 
} 

Jetzt ist meine Frage, was die „eleganteste“ Lösung ist, die ExponentialSmoother mit nur einem Template-Parameter (der Elementtyp) zu implementieren? Es sollte mit Eigenvektoren und Matrizen, aber auch mit Fließkommatypen funktionieren.

Mit anderen Worten, ist es möglich zu überprüfen, ob Elemtype :: Scalar existiert und wenn nicht (d. H. Elemtype ist float oder double) definieren Sie den Floattype als Elemtype?

Eine ähnliche Frage wurde gestellt here. Aber ich frage mich, was die allgemeinste Lösung ist, wenn zum Beispiel STL-Vektoren ebenfalls unterstützt werden sollten. Würden alle Typen dasselbe geschachtelte typedef (oder einige Eigenschaften Klasse mit konsistenter Benennung) benötigen?

+0

* Würden alle Typen die gleiche geschachtelte typedef (oder einige Traits-Klasse mit konsistenter Benennung) benötigen? * - Ja. –

Antwort

3

Sie können einen Helfer verwenden. Der Link hat man fast enthält die Lösung:

template<class T, class R = void> 
struct enable_if_type 
{ 
    typedef R type; 
}; 

template<class E, class Enable = void> 
struct GetFloatType 
{ 
    typedef E type; 
}; 

template<class E> 
struct GetFloatType<E, typename enable_if_type<typename E::Scalar>::type> 
{ 
    typedef typename E::Scalar type; 
}; 

Dann in Ihrer Klasse:

template <class Elemtype, class Floattype = typename GetFloatType<Elemtype>::type> 
class ExponentialSmoother 
{ 
    // ... 
}; 

Auch bei diesen Benutzern können weiterhin zur Verfügung stellen manuell ihren Schwimmer-Typen. Sie können es live sehen. Bonus: Arbeitet mit C++ 03 ohne Probleme.

Beachten Sie, dass Sie weitere Teilspezialisierungen von GetFloatType hinzufügen können. Here is a live example. Vergessen Sie nicht, dass ElemType akzeptabel sein muss für nur eine Spezialisierung von GetFloatType, sonst wird es mehrdeutig sein (und einen Compilerfehler verursachen).

+0

Danke, das ist in der Tat eine sehr elegante Lösung. Nun, wenn ich andere Matrix-Typen unterstützen möchte, kann ich grundsätzlich weitere Template-Spezialisierungen hinzufügen, zB: 'template struct GetFloatType :: type> {...} .' – spinxz

+0

Ja, Sie können weitere Spezialisierungen hinzufügen. Siehe meine Bearbeitung (Ende der Antwort). – Synxis