2016-08-03 15 views
15

Ich frage mich, ob es möglich ist, eine einzelne (und mögliche doppelte) verkettete Liste mit std::experimental::optional zu implementieren.Verwenden Sie std :: experimental :: optional, um eine Liste zu implementieren

template <typename T> 
struct node { 
    std::experimental::optional<node<T>> next; 
    T data; 
}; 

Was sind die Vor- und Nachteile eines solchen Designs? Könnten neue Funktionen c++1z verwendet werden, um Sentinels zu implementieren oder sie insgesamt loszuwerden? Würde dies auch auf n-stufige Bäume skalieren?

+1

Haben Sie es versucht? Sieht so aus, als würde der erste Knoten alle anderen als Werte anstelle von Zeigern enthalten? Nicht sicher, wie gut das skalieren wird. – stijn

Antwort

18

Es ist nicht möglich, eine verkettete Liste auf diese Weise zu implementieren, da Ihr node-Typ immer unvollständig ist. Hier ist ein more complete example, die das Problem veranschaulicht:

#include <iostream> 
#include <experimental/optional> 

template <typename T> 
struct node { 
    std::experimental::optional<node<T>> next; 
    T data; 
}; 

int main(int, char **) 
{ 
    std::cout << sizeof(node<int>) << std::endl; 
    return 0; 
} 

Der Punkt ist, dass optional<T>T vollständig sein erfordert aber an dem Punkt, wo Sie next definieren, node ist unvollständig. Der Grund, warum optional<T> einen vollständigen Typ benötigt, besteht darin, dass T direkt innerhalb des optional-Objekts gespeichert wird, d. H. Speicher auf dem Heap wird nicht zugewiesen. Als Ergebnis muss es die Größe T kennen. Intern enthält es einen Puffer von sizeof(T). In Bezug auf die Speicherlayout können Sie denken optional<T> als

template <class T> 
struct optional 
{ 
    bool _containsValue; 
    char _buffer[ sizeof(T) ]; 
}; 

aber in der Praxis ist es komplizierter ist, aufgrund von Speicherausrichtungsanforderungen.

In Ihrem Fall, um die Größe von optional<node> zu kennen, muss es die Größe von node kennen und dafür muss es die Größe von optional<node> kennen.

10

Es ist unmöglich, weil die T erfordert, um abgeschlossen zu sein.

Per N3672 (Vorschlag für std::optional):

Vorlage Klasse optional erlegt wenig Anforderungen an T: Er hat entweder ein L-Wert Referenztyp oder ein kompletter Objekttyp, das die Anforderungen von Destructible sein.

+2

Das heißt, 'sizeof (node)' muss mindestens 'sizeof (next) + sizeof (data)' sein und 'sizeof (next)' muss größer sein als 'sizeof (node)' ... – rodrigo

+0

Hat die gleiche Anforderung halten für '' std :: experimental :: variant''? – fuji

+1

@ j.dog Nicht sicher über die 'std :: experimental :: variant', aber' boost :: variant' erfordert vollständige Typen (wenn nicht 'boost :: recursive_variant' verwendet wird, die dynamische Zuweisung verwendet, um sie außerhalb von zu speichern das Objekt). – milleniumbug