2011-11-02 9 views
5

Ho una classe di base template in questo modo:Limita una funzione basata su modelli ai tipi di base e derivati?

template<typename T, std::size_t Size> 
class VectorT 
{ 
public: 
    typedef T data_type; 
} 

e un paio di classi derivate specializzate:

template<typename T> 
class Vector2d : public VectorT<T, 2U> 
{ // some specialised functions } 

template<typename T> 
class Vector3d : public VectorT<T, 3U> 
{ // some other specialised functions } 

e questi funzionano bene. Howerver, ho alcune funzioni indipendenti per gli operatori. Per esempio:

template<typename T, size_t Size> 
VectorT<T, Size> operator*(T lhs, const VectorT<T, Size>& rhs) 
{ 
    ... 
} 

Purtroppo questi non funzionano per le mie classi derivate, perché restituiscono un VectorT<T, Size> invece di un Vector2d<T>.

così ho provato con

template<V> 
V operator*(typename V::data_type lhs, const V& rhs) 
{ 
    ... 
} 

e questo funziona bene, ma può portare ad ambiguità perché aspira qualsiasi altra cosa con un membro data_type.

Come posso aggirare questo: come posso scrivere funzioni di sicurezza del tipo che funzionano solo con la mia base vettoriale, o qualsiasi derivata di?

Sto cercando di evitare di dover ripetere nuovamente e ridefinire gli operatori per le sottoclassi.

risposta

7

si potrebbe aggiungere ancora un'altra classe di base, uno che è indipendente dai parametri di modello, e utilizzare SFINAE per disabilitare le chiamate per i tipi diversi derivato da tale base:

struct VectorBase {}; 

template< typename T, std::size_t Size > 
class VectorT : public VectorBase { ... } 

template< typename V > 
typename boost::enable_if< boost::is_base_of< VectorBase, V >, V >::type 
operator*(V lhs, V const& rhs){ ... } 

noti che is_base_of< X, X > è sempre true, quindi questa funzione funzionerà per un tipo in più del necessario, ovvero la classe base VectorBase.

Se si utilizza un compilatore che implementa TR1, è possibile sostituire boost:: per std:: in entrambi i punti in cui viene utilizzato.

+1

Grazie, questa è la seconda volta che questa sera mi hai dato una risposta che coinvolge la SFINAE; Penso che sia qui che risiedono le lacune nelle mie conoscenze! Non sono sicuro di come enable_if funzioni ancora, ma ha funzionato molto bene. Grazie ancora. – DanDan

+0

@Kballo: per quanto riguarda la sostituzione di 'boost ::' di 'std ::' -> nota che 'std :: enable_if' è un equivalente rigoroso per' boost :: enable_if_c', quindi dovresti "scartare" il ' membro 'value' di' is_base_of' quando passi a 'std ::'. –

1

Sei in una situazione insolita da cui non esiste un modo "carino". È possibile:

  1. Controllare il tipo in fase di esecuzione (o tempo di compilazione, spinta probabilmente può farlo)
  2. Prendere una e l'uso VectorT<>& che invece di creare un nuovo VectorT all'interno della funzione e il ritorno. In questo modo puoi anche prendere sottoclassi di VectorT come riferimento. Questo ti renderebbe necessario usare una funzione invece di un operatore.
  3. Fai quello che ha detto K-ballo.
+1

Mi piace di più l'opzione 3: P –

Problemi correlati