8

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...)

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 1
    Ok, but even in `-std=c11` this does not work – Basile Starynkevitch Feb 23 '16 at 07:03
  • 1
    [This question](http://stackoverflow.com/questions/24743520/incompatible-pointer-types-passing-in-generic-macro) has a similar problem and the top answer probably answers your question – M.M Feb 23 '16 at 07:17
  • Other answers on the same topic seem to suggest that the other cases are not allowed to contain a *constraint violation* (wrong type for initializer is indeed one of those) – M.M Feb 23 '16 at 07:25
  • 1
    As a side note, with those function declarations you have already restricted the type, so there's no need for _Generic here. `ty from_double(double x) { return (ty){.d=x}; }` and so on does the job. – Lundin Feb 23 '16 at 07:45

1 Answers1

5

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,     \
                            double: 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.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177