2 ms·
> Not very convincing. Sorry, I was in a hurry when I wrote that comment :) The easiest way is to take advantage of the fact that a pointer to a union can be
by comex 9y ago
> Not very convincing.
Sorry, I was in a hurry when I wrote that comment :)
The easiest way is to take advantage of the fact that a pointer to a union can be casted to a pointer to one of its members (C11 6.7.2.1.16), or in other words that all the possible variants are at the same offset. So we can do:
typedef struct Some variantof_SomeOne;
#define as(x, T) ((struct T *)variant_cast(x, tag(T), \
offsetof(variantof_##T, u)))
where the definition of Some would have to be changed to give the union field a name, and variant_cast would add the offset given as an argument.
An alternative would be one of the options you mentioned, a boilerplate function. But it doesn't have to be 'real' boilerplate: it's possible to use macros to automate the definition of such functions. Given suitable macros, you can write something like:
#define FOO_FIELDS(f) \
f(one, struct bar) \
f(two, float) \
f(three, int)
DEFINE_VARIANT(foo, FOO_FIELDS)
and get as much boilerplate as you want, like:
enum foo_tag { foo_tag_one, foo_tag_two, foo_tag_three };
struct foo {
enum foo_tag tag;
union {
struct bar one;
float two;
int three;
};
};
static inline bool
foo_is_one(struct foo *fo) {
return foo->tag == foo_tag_one;
}
static inline struct bar *
foo_get_one(struct foo *foo) {
assert(foo->tag == foo_tag_one);
return &foo->one;
}
[etc. for other variants]