2012-03-25 8 views
11

Ich habe einen rekursiven Datentyp wie folgt aus:Templat rekursiven Datentypen

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

SomeType<int> foo; 

Dies funktioniert gut, aber wegen eines unvollständigen Typ in einem Compiler-Fehler std::map mit std::unordered_map Ergebnisse zu ersetzen. Bin ich (oder gcc) irgendwo einen Fehler gemacht? oder ist das nur ein Teil des Standards?

Ich würde auch von einem Template-Parametern (wie std::stack und std::queue) bestimmt wie den inneren Behälter haben, aber ich kann nicht einen Weg finden, um es zu tun, da die Sometype erfordern würde bereits definiert werden.

Unvollständige Beispiel:

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

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

Ich weiß, das mit Laufzeit indirection getan werden kann, aber das ist nicht das, was ich suche.

+1

Die Standardbibliothek Container-Vorlagen erfordern, dass Sie sie mit kompletten Typen instanziiert; alles andere ist undefiniertes Verhalten. Du musst damit leben. Sie können jedoch eine pimpl-Lösung verwenden, um das zu umgehen. –

+0

@KerrekSB Ist das so? Verdammt, ich habe regelmäßig N-Bäume geschrieben, deren Knoten im Sinne von 'std :: vector children' implementiert wurden. –

+0

@KonradRudolph: Nun, Sie müssen sicherstellen, dass bei der Instanziierungszeit der Typ abgeschlossen ist. Das könnte ein subtiles Problem sein. –

Antwort

7

Ihre Klasse ist nirgendwo vor der endgültigen } ihrer Definition unvollständig. Das Element verwendet daher den unvollständigen Typ SomeType in den Vorlagenargumenten des Typs.

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

Ihre zweite Frage fällt unter der gleichen Antwort - es illegal ist, dass in erster Linie zu tun.

+0

Hmm. Leider verstehe ich das Argument des Artikels nicht, warum 'std :: map ' mit unvollständigen Typen prinzipiell nicht funktionieren kann. Ist das nicht sehr ähnlich wie 'std :: vector >', das kann prinzipiell funktionieren ('std :: pair ' ist unvollständig)? Gleiches gilt für die anderen Container. –

+0

Wenn das eine Erklärung braucht, schlage ich vor, einen Chatraum zu öffnen, es ist nicht schwer, einfach nicht geeignet für den Kommentarbereich ... Nun, wie öffne ich explizit einen Chatroom dazu ... – Irfy

+1

Lasst uns hier chatten: http://chat.stackoverflow.com/rooms/9282/stl-with-incomplete-types – Irfy

4

Sie können aus offensichtlichen Gründen keine Vorlage mit rekursiven Standardparametern definieren. Sie können auch keine standardmäßigen Bibliothekscontainervorlagen für unvollständige Typen instanziieren, da der Standard dies angibt (andernfalls ist das Verhalten nicht definiert). obwohl die übliche PIMPL Idiom kann helfen:

#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

Die Bibliothek boost :: container bietet Alternativen für die meisten STL-Typen, die rekursive Container mit unvollständigen Typen zulassen. Es bietet derzeit keine unordered_map – mark

+0

@mark: Danke, das ist gut zu wissen! –

3

Während Sie nicht unvollständigen Typen mit Containern verwenden können, können Sie es mit Smart-Pointer zu tun. Und während Sie nicht Template-Typen mit undefinierten Typen Parameter erstellen können, können Sie einige Tricks, hier verwenden:

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

Ist es möglich, die erste Zeile so zu ändern, dass der Standardwert für den Container std :: vector wäre? –

+0

@NielsLohmann, technisch können Sie schreiben 'Vorlage Klasse Container = Std :: Vektor>', aber es wäre inkonsistent mit 'std :: unordered_map' als. Weil map _assosiative_ container und vector nur ein Array ist. – Lol4t0