Ich bezweifle, dass es wie erwartet funktioniert.
Sie haben Recht. Es wird nicht. Zuerst wird es nicht kompilieren, wenn Sie jemals versuchen, eine Node
zu konstruieren. Sie werden so etwas wie erhalten:
prog.cc:26:10: error: call to implicitly-deleted default constructor of 'Node'
Node n;
^
Das ist, weil in einem union
, werden alle nicht-trivialen Operationen implizit gelöscht. Sie müssen ~Value()
definieren, um das Richtige zu tun. Unter der Annahme type
ist der Index, welches Element in der Union wir tatsächlich sind, um das einzuschalten und den entsprechenden Destruktor aufzurufen. Und dann das Gleiche zum Kopieren und Verschieben.
Das heißt, die Verschachtelung von unvollständigen Typen ist auch nicht in Ordnung. vector
darf einen unvollständigen Typ haben, solange er vor der ersten Verwendung vollständig ist. Aber unordered_map
hat diese Erlaubnis nicht. Sie müssen den Werttyp in etwas anderes einbetten - z. B. oder shared_ptr<Node>
.
Was Sie in Value
haben, ist ein gemeinsames Muster, das eine Million verschiedene Namen hat: diskriminierte Union, Sum Typ, oder am häufigsten variant
. Anstatt das Rad neu zu erfinden, schlage ich vor, dass Sie statt dessen std::variant
verwenden (wenn Sie einen neueren Compiler verwenden, um so etwas zu unterstützen) oder boost::variant
(sonst). Damit haben Sie:
using Value = variant<int32_t, float, bool,
std::vector<Node>, std::unordered_map<std::string, Node>>;
und diese Art ist bereits zerstörbar, kopierbar, beweglich und besuchbar für Sie.
Gewerkschaften behandeln Konstruktoren und Destruktoren nicht. Daher ist die Verwendung einer Union mit einem Nicht-POD unsicher (std :: vector ist unsicher). siehe std :: variant und boost :: variant –
Nicht verwandt mit Ihrer Frage, aber warum verwenden Sie 'typedef struct ...'? Strukturen sind wie Klassen und der Strukturname ist ein Typ wie ein Klassenname. –
Weil ich aus einer C-Welt kam. – Ariel