2012-11-22 6 views
5

Si consideri la classe di modello esponenziale più morbida di seguito. Questa classe serve per uniformare/filtrare i dati sequenziali in modo esponenziale (vedi metodo di aggiornamento). Elemtype potrebbe essere un vettore e Floattype è solitamente uno scalare. Per esempio.C++ controlla il typedef annidato di un parametro del modello per ottenere il suo tipo di base scalare

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

In questo esempio il secondo parametro modello Floattype potrebbe essere evitato perché la classe Matrix di Eigen contiene un typedef nidificato per ottenere il tipo di base scalare:

Vector2f::Scalar 

E 'anche ragionevole per istanziare sia Elemtype e Floatype come galleggia per lisciare dati unidimensionali. In questo caso, potrebbe essere saltato anche il secondo parametro template.

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

Ora la mia domanda è che cosa è la soluzione "più elegante" per l'attuazione del ExponentialSmoother con un solo parametro di modello (il tipo di elemento)? Dovrebbe funzionare con i vettori Eigen e le matrici ma anche con i tipi a virgola mobile.

In altre parole, è possibile verificare se Elemtype :: Scalar esiste e se non lo è (cioè Elemtype è float o double) definire il Floattype come Elemtype?

Una domanda simile è stata posta here. Ma mi chiedo quale sia la soluzione più generica se per esempio i vettori STL debbano essere supportati. Tutti i tipi richiederebbero lo stesso typedef annidato (o qualche classe di tratti con denominazione coerente)?

+0

* Tutti i tipi richiedono lo stesso typedef annidato (o qualche classe di tratti con denominazione coerente)? ​​* - Sì. –

risposta

3

È possibile utilizzare un helper. Il link che hai dato quasi contiene la soluzione:

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

Poi, nella tua classe:

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

Inoltre, con questo gli utenti possono comunque fornire manualmente il loro tipo float. Lo puoi vedere live. Bonus: funziona con C++ 03 senza problemi.

Nota che è possibile aggiungere ulteriori specializzazioni parziali di GetFloatType. Here is a live example. Non dimenticare che ElemType deve essere accettabile per solo una specializzazione di GetFloatType, altrimenti sarà ambiguo (e causa un errore del compilatore).

+0

Grazie, questa è davvero una soluzione molto elegante. Ora, se volessi supportare altri tipi di Matrix, potrei fondamentalmente aggiungere altre specializzazioni di template, ad esempio: 'template struct GetFloatType :: type> {...} .'' – spinxz

+0

Sì, è possibile aggiungere ulteriori specializzazioni. Vedi la mia modifica (fine della risposta). – Synxis