2009-07-15 3 views
8

Ho una classe contenitore, che chiameremopuntatori come parametri del modello?

template <class T> CVector { ... } 

voglio fare qualcosa di diverso con questa classe quando T è un tipo di puntatore, ad esempio, qualcosa sulla falsariga di:

template <class T*> CVector< SomeWrapperClass<T> >; 

dove SomeWrapperClass si aspetta il tipo di oggetto puntato come suo parametro. Sfortunatamente, questa sintassi non funziona e con alcuni scavi non ho trovato un buon modo per far funzionare qualcosa del genere.

Perché farlo in questo modo? Voglio cambiare, in un'applicazione molto grande, come funzionano alcuni dei nostri contenitori quando il tipo su cui si specializzano è un puntatore rispetto a un puntatore e, idealmente, mi piacerebbe farlo senza modificare i ~ 1000 punti nel codice in cui ci sono cose come CVector<Object*> vs CVector<int> o alcuni di questi - e giocare con specializzazioni parziali sembra essere la strada da percorrere.

Sono in pausa qui?

+0

Penso che sia necessario più contesto per quello che stai facendo. Quindi, a cosa serve? Cos'è la classe wrapper "Some"? E qual è 'CVector'? Non un 'std :: vector' reinventato, spero. – GManNickG

+0

No, non lo è - sto usando intenzionalmente nomi astratti per le classi - ma fondamentalmente la classe wrapper accetta come parametro un tipo non puntatore. CVector può prendere qualsiasi tipo di tipo - voglio solo usare la classe wrapper quando al vettore viene dato un tipo di puntatore. –

+0

@D Garcia: Non capisco cosa vuoi, esattamente. Se T è un puntatore, cosa dovrebbe fare CVector? – rlbond

risposta

4

Non penso che si possa specializzare una classe usando la sintassi che si descrive ... Non so come possa funzionare. Quello che puoi fare è specializzare la classe per i puntatori e ri-implementare il suo coraggio usando la classe wrapper attorno ai puntatori grezzi. Non sono sicuro che possa essere d'aiuto, ma this article descrive modelli specializzati per i puntatori.

+0

Grazie - l'articolo che hai collegato mi ha dato un modo per fare ciò di cui ho bisogno. –

+0

Contento di aver potuto aiutare. Non credo che ti piacerebbe accettare la mia risposta, o almeno dare un voto, per mostrare apprezzamento? :) – rmeador

+0

Buon collegamento, avere un uphote postumo XP – jaypb

0

Non penso che i modelli siano abbastanza flessibili.

Un approccio forza bruta sarebbe quello di specializzarsi per tutti i tipi di puntatore ... che sconfigge il problema dell'utilizzo di modelli.

Si potrebbe avere una classe CVector diversa che viene utilizzata solo per i vettori di puntatori?

+0

Se facessi un tipo diverso, dovrei passare attraverso tutti i punti del codice in cui è stato usato il vecchio tipo per capovolgerlo al nuovo tipo - meno che ideale , sto cercando una sostituzione. –

7

Se ho capito bene, questo potrebbe fare quello che vuoi:

template<typename T> 
class CVector { ... }; 

template<typename T> 
class CVector<T*> : public CVector< SomeWrapperClass<T> > { 
public: 
    // for all constructors: 
    CVector(...) : CVector< SomeWrapperClass<T> >(...) { 
    } 
}; 

Si aggiunge un ulteriore livello di eredità per ingannare CVector<T*> in essere un CVector< SomeWrapperClass<T> >. Ciò potrebbe anche essere utile nel caso in cui sia necessario aggiungere ulteriori metodi per garantire la piena compatibilità tra l'interfaccia prevista per T* e l'interfaccia fornita per SomeWrapperClass<T>.

+0

Hmm - se posso avere il nome della nuova classe come il vecchio - questo potrebbe funzionare. Se devo rinominare la classe, torno a dover cambiare tutte le istanze in una nuova classe, che è lavoro che sto cercando di evitare di dover fare. –

+0

È ancora solo un 'CVector <...>', solo che potrebbe ereditare da un diverso 'CVector <...>' internamente. Ma gli utenti della classe non dovrebbero preoccuparsi di questi dettagli interni, a patto che l'interfaccia rimanga compatibile. – sth

+0

+1 @Garcia: la soluzione di cui sopra dovrebbe funzionare - puoi fare riferimento al tuo utilizzo del modello CVector come CVector vs CVector - e verrà utilizzato il modello appropriato (implementato in termini di SomeWrapper –

4

Questo funziona bene in C++ ...

#include <iostream> 

template <class T> 
class CVector 
{ 
public: 
    void test() { std::cout << "Not wrapped!\n"; } 
}; 

template <class T> 
class CVector<T*> 
{ 
public: 
    void test() { std::cout << "Wrapped!\n"; } 
}; 

int main() 
{ 
    CVector<int> i; 
    CVector<double> d; 
    CVector<int*> pi; 
    CVector<double*> pd; 
    i.test(); 
    d.test(); 
    pi.test(); 
    pd.test(); 
} 
+0

). lasciatemi modificare un parametro template condizionatamente sull'opportunità o meno di un puntatore: ho già visto cosa ha boost. Questo non è un caso di codice condizionale - è un caso di tipizzazione condizionale - i tipi di cose all'interno della classe devono essere diversi in base al fatto che il parametro template sia o meno un puntatore. –

1

Il Boost type traits library può aiutare a raggiungere questo obiettivo. Controlla il tratto di tipo is_pointer.

#include <boost/type_traits.hpp> 
#include <iostream> 
#include <vector> 

using namespace std; 

template <class T> 
class CVector { 
    public: 
    void addValue(const T& t) { 
     values_.push_back(t); 
    } 

    void print() { 
     typedef boost::integral_constant<bool, 
     ::boost::is_pointer<T>::value> truth_type; 

     for (unsigned int i = 0; i < values_.size(); i++) 
     doPrint(values_[i], truth_type()); 
    } 


    private: 
    void doPrint(const T& t, const boost::false_type&) { 
     cout << "Not pointer. Value:" << t << endl; 
    } 

    void doPrint(const T& t, const boost::true_type&) { 
     cout << "Pointer. Value: " << *t << endl; 
    } 

    std::vector<T> values_; 
}; 


int main() { 
    CVector<int> integers; 
    integers.addValue(3); 
    integers.addValue(5); 
    integers.print(); 

    CVector<int*> pointers; 
    int three = 3; 
    int five = 5; 
    pointers.addValue(&three); 
    pointers.addValue(&five); 
    pointers.print(); 
} 
0

Sono d'accordo con la risposta di rlbond. L'ho modificato un po 'per soddisfare le tue necessità. CVector può essere una classe derivata del CVector stesso. È quindi possibile utilizzare diversi membri e funzioni per esso.

#include <iostream> 
#include <string> 
template <class T> 
class CVector 
{ 
public: 
    void test() { std::cout << "Not wrapped!\n"; } 
    void testParent() { std::cout << "Parent Called\n";} 
}; 

template <class T> 
class CVector<T*>: 
    public CVector<T> 
{ 
public: 
    void test(std::string msg) { std::cout << msg; testParent(); } 
}; 

int main() 
{ 
    CVector<int> i; 
    CVector<double> d; 
    CVector<int*> pi; 
    CVector<double*> pd; 
    i.test(); 
    d.test(); 
    pi.test("Hello\n"); 
    pd.test("World\n"); 
    system("pause"); 
}