2016-02-23 12 views
8

voglio usare la parola chiave C11_Generic per riempire un sindacato in base al tipo statico, come:_Generic per riempire un po 'di unione

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);} 

ma questo non viene compilato, ad esempio, GCC 5.3 dà (con 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, utilizzando gcc -std=c99 -Wall dà lo stesso errore ...

o è _Generic utile solo per tgmath.h?

ho pensato che _Generic sceglie l'espressione a seconda del tipo compilatore noto, in modo che il non-sensical (ty){.s=(x)} sarebbero ignorati in from_double ....

(se questo ha funzionato, sarei in grado di "sovraccarico" make_ty secondo la statica, compilatore noto, tipo dell'argomento ...)

+1

Ok, ma anche in '-std = c11' questo non funziona –

+1

[Questa domanda] (http://stackoverflow.com/questions/24743520/incompatible-pointer-types-passing-in-generic-macro) ha un problema simile e la risposta più alta probabilmente risponde alla tua domanda –

+0

Altre risposte sullo stesso argomento sembrano suggerire che gli altri casi non siano autorizzati a contenere una violazione * del vincolo * (il tipo errato per l'inizializzatore è effettivamente uno di quelli) –

risposta

5

Tutti i rami della _Generic devono essere codice valido, così come in qualcosa di simile if (1) { here; } else { there; }. Per avere una soluzione si potrebbe prendere il contrario. Definire funzioni simili a:

inline ty from_double(double x) { return (ty){ .d = x }; } 

per tutti i vostri casi e quindi avere la macro come:

#define make_ty(X) _Generic((X),      \ 
          double: from_double,  \ 
          double: from_long,  \ 
          ...)(X) 

Con la visibilità attraverso inline compilatori sono in realtà in grado di ottimizzare tale codice e di solito non passare attraverso chiamando il puntatore della funzione.