2011-10-01 14 views
12

Vorrei definire una specializzazione del modello C++ che si applica a tutte le sottoclassi di una determinata classe base. È possibile?per tutte le sottoclassi

In particolare, mi piacerebbe farlo per l'hash STL <>. hash <> è definito come un modello parametrizzata vuoto, e una famiglia di specializzazioni per tipi specifici:

template<class _Key> 
    struct hash { }; 

template<> 
    struct hash<char> 
    { 
    size_t 
    operator()(char __x) const 
    { return __x; } 
    }; 

template<> 
    struct hash<int> 
    { 
    size_t 
    operator()(int __x) const 
    { return __x; } 
    }; 
... 

vorrei definire qualcosa di simile:

template<class Base> 
    struct hash { 
    size_t operator()(const Base& b) const { 
     return b.my_hash(); 
    } 
    }; 

class Sub : public Base { 
    public: 
    size_t my_hash() const { ... } 
}; 

ed essere in grado di usarlo come this:

hash_multiset<Sub> set_of_sub; 
set_of_sub.insert(sub); 

Tuttavia, il mio modello di hash è in conflitto con quello generico di STL. Esiste un modo (forse usando i tratti) per definire una specializzazione del modello che si applica a tutte le sottoclassi di una data classe base (senza modificare le definizioni STL)?

Nota che so di poter fare questo con alcuni parametri di modello in più ogni volta che è necessario questa specializzazione hash, ma vorrei evitare questo, se possibile:

template<> 
    struct hash<Base> { 
    size_t operator()(const Base& b) const { 
     return b.my_hash(); 
    } 
    }; 

.... 

// similar specialization of equal_to is needed here... I'm glossing over that... 
hash_multiset<Sub, hash<Base>, equal_to<Base> > set_of_sub; 
set_of_sub.insert(sub); 
+0

se è in conflitto perché non utilizzare uno spazio dei nomi? – Arunmu

+1

Un possibile duplicato di http://stackoverflow.com/questions/1032973/how-to-partially-specialize-a-class-template-for-all-derived-types –

+0

... dove la soluzione è il nome di tutti i classi derivate in modo simile, che non è abbastanza soddisfacente. – jpalecek

risposta

1

La soluzione è quella di utilizzare SFINAE per decidere se consentire o meno la specializzazione in base alla struttura di ereditarietà della classe. In Boost è possibile utilizzare enable_if e is_base_of per implementarlo.

+0

Ho paura che tu non possa usare 'enable_if' in questo caso particolare. – jpalecek

+0

jpalecek: Perché no? A proposito, se boost è la risposta qui, potrebbe non aiutarmi comunque, dal momento che il mio posto di lavoro limita le librerie che possiamo usare, e boost :: enable_if non fa parte del sottoinsieme prescritto. –

+0

Quindi potrebbe essere necessario eseguire il rollover, ma si dovrebbe essere in grado di ottenere qualcosa che funzioni come si desidera usando SFINAE. – KayEss

0

questo era il meglio che potessi fare:

template<> 
    struct hash<Sub> : hash<Base> { 
    }; 

Sono un po 'preoccupato che non ho dovuto fare operator() virtuale, anche se .