Here is a type I declared:
(I declared t_sphere
, t_cylinder
and t_triangle
too)
typedef struct s_intersection{
double t1;
double t2;
int id;
union {
t_sphere sph;
t_cylinder cyl;
t_triangle tri;
} u;
} t_intersection;
When I use that intersection structure in some code, is there a handy way to refer to the member inside my union ?
e.g. Let's say I want to write a function that acts differently according to the type of geometric_figure it contains. Will I have to do it like this ?
if (geometric_figure_id == SPHERE_ID)
// I know I will have to refer to p->u with p->u.sph...
else if(geometric_figure_id == CYLINDER_ID)
// I know I will have to refer to p->u with p->u.cyl...
else if (geometric_figure_id == TRIANGLE_ID)
// I know I will have to refer to p->u with p->u.tri...
What if I had 10 different geometric_figures types inside my union ?
This feels very heavy.
Do you have a more elegant solution ?
Let's say I want to write a function that acts differently according to the type of geometric_figure it contains. Will I have to do it like this ?
It sounds like an awareness of other languages' support for runtime polymorphic function dispatch may be part of the context for your question. If so, then it's important to recognize that what you're dispatching on here is not the type of any object, as you typically would in (say) C++ or Java, but rather the value of an integer.
If you want to follow different control paths for different runtime values of an integer, then there is no alternative to writing a flow-control statement -- generally an if
/ else if
/ else
or a switch
-- that directs control appropriately.*
Now, if you were dispatching on type then C does offer type-generic expressions. For the most part, these make sense to use only inside a macro:
#define VOLUME(x) _Generic((x), \
t_sphere: 4 * PI * (x).r * (x).r * (x).r / 3, \
t_cylinder: PI * (x).r * (x).r * (x).h, \
t_cube: (x).edge * (x).edge * (x).edge \
)
In contexts other than a macro, you know the type involved already, so a type-generic expression gains you nothing worth having.
Depending on how much macro magic you want to apply, there are ways avoid writing out long if
/ else if
/ else
statements or long switch
statements by hand. Type-generic macros would likely play a role in something like that. But such a course of action is difficult to implement well. You're more likely to end up with a confusing maintenance nightmare of complex macro stacks than with something that would compare favorably to manually-written switch
statements.
*Or maybe a complex expression with nested use of the ternary operator could be taken as fullfilling that need, but using such an expression is not realistic if it needs to be written and maintained by hand.