3 ms·
A method on a union is much less useful when you can't match on the tag though. I suppose you could store tag inside the union. Is that common? I've always imag
by nicoburns 4y ago
A method on a union is much less useful when you can't match on the tag though. I suppose you could store tag inside the union. Is that common? I've always imagined C/C++ tagged unions would store tag outside the union.
- School-Cotton 4y agoYes, it’s very common. The difference is rust enforces via the type system that you match on it.
- dilap 4y agoi haven't done c++ in a million years, but huh, you can! can't have any types w/ non-trival copy constructors in a union, though, apparently, which is quite the restriction. https://gist.github.com/erinok/c823af95db408653c7e42ab1893073b7 https://gist.github.com/erinok/c823af95db408653c7e42ab189307...
- ivmaykov 4y agoI may be wrong, but I thought it’s that you can’t have any fields with non trivial destructors, because the union wouldn’t know which destructor to call. So POD types / raw pointers / arrays of the above / structs of the above are allowed, and that’s pretty much it.
- gpderetta 4y agoYou can have non trivial types in an union, but you need to explicitly define constructor in the union or the containing type (i.e. the default union copy constructor and assignment operator are disabled).
- jcranmer 4y ago> can't have any types w/ non-trival copy constructors in a union, though, apparently, which is quite the restriction. That was removed in C++11. The rule now is: > Absent default member initializers ([class.mem]), if any non-static data member of a union has a non-trivial default constructor ([class.default.ctor]), copy constructor, move constructor ([class.copy.ctor]), copy assignment operator, move assignment operator ([class.copy.assign]), or destructor ([class.dtor]), the corresponding member function of the union must be user-provided or it will be implicitly deleted ([dcl.fct.def.delete]) for the union. i.e., you need to provide an explicit version of the special function for the union if any member has a nontrivial implementation.
- dilap 4y agoah, good to know, thanks! unfortunately too late to edit my comment
- ivmaykov 4y agoYou would probably use std::variant in C++ if you want tagged unions. So you could have a struct or class with one std::variant field and some methods which can match on the type of the variant. But it would be kind of clunky.
- unwind 4y agoAt least in C, you cannot store a tag inside the union since all fields of the union live at the same offset (0) they tag will be smashed by the actual value it's trying to talk about. In C, you have to wrap the union in a struct in order to add the tag, and that pattern is fantastically common. Let's have a little geometry-inspired example: typedef enum { SHAPETYPE_RECTANGLE, ... } ShapeType; typedef struct { ... } Rectangle; typedef struct { ... } Circle; typedef struct { ... } Triangle; typedef struct { ... } Polygon; typedef struct { // Outer struct, not a union at this level. ShapeType type; union { Rectangle rectangle; Circle circle; Triangle triangle; Polygon polygon; } // This can be nameless in new(ish) C, which is nice. } Shape; Then you'd create a value like this, maybe: Shape rect = { .type = SHAPETYPE_RECTANGLE, .rectangle = { 0, 0, 20, 10 } }; Of course wrapping the initialization in a function would make it nicer. The above union-in-a-struct wrapping is my mental model for how enums work in Rust, but I still find it jarring. :)
- tialaramex 4y agoI'm not certain for C, but definitely in C++ it's legal to union a bunch of structures with a common prefix, and then talk about the prefix in the "wrong" variant and that's OK. There may be some restrictions about exactly what is in that prefix, but at least obvious things like an enum or an integral type will work. So for your example you put ShapeType type in each of Rectangle, Circle, Triangle etc. and then you can union all of them, and the language promises that shape.circle.type == Rectangle is a reasonable thing to ask, so you can use that to make a discriminated union.
- planede 4y agoC++ allows accessing inactive members in the special case when the active member shares a "common initial sequence" with the particular inactive member. So yeah, it's possible to store the tag in the common initial sequence of all the union members. This is quite niche and rarely used. Most of the time it makes more sense to have the tag outside. Sometimes the tag in the common initial sequence allows the whole data structure to pack better than with a tag outside of the union.