I want to use the C11 _Generic
keyword to fill an union according to the static type, like:
typedef union {
double d;
long l;
const char*s;
void*p;
} ty;
#define make_ty(X) _Generic((X), \
double: (ty){.d=(X)}, \
long: (ty){.l=(X)}, \
const char*: (ty){.s=(X)}, \
default: (ty){.p=(X)})
ty from_double(double x) { return make_ty(x); }
ty from_string(const char*s) { return make_ty(s); }
ty from_long(long l) { return make_ty(l);}
but this does not compile, e.g. GCC 5.3 gives (with gcc -std=c11 -Wall
):
u.c: In function ‘from_double’:
u.c:11:35: error: incompatible types when initializing type ‘const char *’
using type ‘double’
const char*: (ty){.s=(X)}, \
^
u.c:14:41: note: in expansion of macro ‘make_ty’
ty from_double(double x) { return make_ty(x); }
BTW, using gcc -std=c99 -Wall
gives the same error...
Or is _Generic
only useful for tgmath.h
?
I thought that _Generic
chooses the expression according to the compiler-known type, so the non-sensical (ty){.s=(x)}
would be ignored in from_double
....
(if that did work, I would be able to "overload" make_ty
according the static, compiler-known, type of the argument...)
All branches of _Generic
must be valid code, just as much as in something like if (1) { here; } else { there; }
. To have a solution you could take it the other way around. Define functions similar to:
inline ty from_double(double x) { return (ty){ .d = x }; }
for all your cases and then have the macro as:
#define make_ty(X) _Generic((X), \
double: from_double, \
long: from_long, \
...)(X)
With the visibility through inline
compilers are actually able to optimize such code and will usually not pass through calling the function pointer.