2012-03-25 14 views
11

ho un tipo di dati ricorsiva simili:tipi di dati ricorsivi templated

template<typename T> 
struct SomeType { 
    std::map<T, SomeType<T>> mapping; 
}; 

SomeType<int> foo; 

Questo funziona bene, ma sostituendo std::map con std::unordered_map risultati in un errore di compilazione a causa di un tipo incompleto. Sono (o gcc) facendo un errore da qualche parte? o è solo una parte dello standard?

Vorrei anche avere il contenitore interno determinato da un parametro di template (come std::stack e std::queue), ma non riesco a trovare un modo per farlo perché ciò richiederebbe SomeType essere già definito.

esempio incompleto:

template<typename T, typename C = std::map<T, SomeType<[???]>>> 
struct SomeType { 
    C mapping; 
}; 

SomeType<int, [???]> foo; 

so che questo può essere fatto con riferimento indiretto fase di esecuzione, ma non è quello che sto cercando.

+1

Il contenitore libreria standard modelli richiedono che li un'istanza con i tipi completi; tutto il resto è un comportamento indefinito. Devi vivere con quello. Tuttavia, puoi utilizzare una soluzione Pimpl per ovviare a questo problema. –

+0

@KerrekSB È così? Dannazione, ho scritto regolarmente alberi n-ari i cui nodi sono stati implementati in termini di 'std :: vector children'. –

+0

@KonradRudolph: beh, devi assicurarti che al momento dell'istanziazione il tipo sia completo. Potrebbe essere un problema sottile. –

risposta

7

La classe è incompleta in qualsiasi punto prima della finale } della sua definizione. Quindi il membro mapping utilizza il tipo incompleto SomeType negli argomenti del modello del tipo.

The standard does not allow this, and it is pure luck that it works with some STL containers.

tua seconda domanda cade sotto la stessa risposta - è illegale farlo in primo luogo.

+0

Hmm. Sfortunatamente, non capisco l'argomento dell'articolo sul perché 'std :: map ' con tipi incompleti non possa funzionare in linea di principio. Non è molto simile a 'std :: vector >', che * può * funzionare in linea di principio ('std :: pair ' incompleto)? Lo stesso vale per gli altri contenitori. –

+0

Se questo richiede una spiegazione, suggerisco di aprire una chat room, non è difficile, solo non adatto alla sezione commenti ... Ora, come faccio ad aprire esplicitamente una chat room su questo ... – Irfy

+1

Chattiamo qui: http://chat.stackoverflow.com/rooms/9282/stl-with-incomplete-types – Irfy

4

Non è possibile definire un modello con parametri predefiniti ricorsivi per ovvi motivi. Non è inoltre possibile creare un'istanza di modelli di contenitori di libreria standard su tipi incompleti, poiché lo standard lo dice (altrimenti è un comportamento non definito). Il solito Pimpl può aiutare, però:

#include <map> 
#include <memory> 
template <typename T> class SomeType 
{ 
    typedef std::map<T, SomeType<T>> map_type; 
    typedef std::unique_ptr<map_type> map_ptr; 
    map_ptr pimpl; 
public: 
    SomeType() : pimpl(new map_type) { } 
}; 
+1

La libreria boost :: container fornisce alternative per la maggior parte dei tipi di STL che consentono contenitori ricorsivi di tipi incompleti. Al momento non fornisce una unordered_map – mark

+0

@mark: Grazie, è bello sapere! –

3

Mentre non è possibile utilizzare i tipi incompleti con i contenitori, è possibile farlo con puntatori intelligenti. E mentre non è possibile creare tipi di modello con parametri tipi non definiti, è possibile utilizzare alcuni trucchi qui:

template<typename T, template <typename U, typename V, typename... Args> class Container = std::unordered_map > 
struct SomeType { 
    Container<T, std::unique_ptr<SomeType> > mapping; 
}; 
+0

È possibile modificare la prima riga in modo tale che il valore predefinito per il Container sia std :: vector? –

+0

@NielsLohmann, tecnicamente puoi scrivere 'template class Container = std :: vector>', ma sarebbe incoerente con 'std :: unordered_map' di. Perché la mappa è _assosiative_ conrtainer e il vettore è solo un array. – Lol4t0