1

Using c11 _Generic is there a way to map multiple types to a single value?

eg:

_Generic(e,      \
    A *:    foo_expression, \
    B **:   foo_expression, \
    C:      foo_expression, \
    enum D: bar_expression, \
    void *: bar_expression)

Is there a way to group types? (this isn't valid syntax just to express the intent)

_Generic(e, \
    A *: B **: C:    foo_expression, \
    enum D: void *:  bar_expression)

The reason I ask is args foo and baz can end up being large expressions (which can't necessarily be refactored into functions), so a way to avoid a lot of duplication would be good.


Note:

If there is no supported way using _Generic, I _could_ make a varargs macro to glue multiple args to a single value...

#define GENERIC_TYPE_GLUE3(answer, arg0, arg1) \
    arg0: answer, arg1: answer
#define GENERIC_TYPE_GLUE4(answer, arg0, arg1, arg2) \
    arg0: answer, arg1: answer, arg2: answer
....

... have many of these macros, then use a varargs wrapper to automatically use the right one, see: https://stackoverflow.com/a/24837037/432509

_Generic(e,      \
    GENERIC_TYPE_GLUE(foo_expression, short int, long),
    GENERIC_TYPE_GLUE(bar_expression, float, double))

(See working example: https://gist.github.com/ideasman42/4426f255880ff6a53080)

Community
  • 1
  • 1
ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • I never actually looked into how generic macros work, but what if you defined new macros for the giant `foo` and `baz` expressions? Does something prevent that from working? – user2357112 Apr 26 '15 at 05:16
  • This will work in most cases, it just means the number of single-use macros may multiply out *(and pollute the name-space)*. I'd rather use the example macro to glue multiple types with a single arg. – ideasman42 Apr 26 '15 at 05:24

2 Answers2

3

No, similar to switch there is no syntax foreseen to regroup multiple cases for _Generic. Your regrouping macro approach is probably the correct one for your purpose, then. You may have a look into macro meta programming as is done by boost or my package P99 that allow you to have just one such macro that also does the counting of the cases for.

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

For your use case you can use the type promotion rules

_Generic((e)+0ULL,             \
    unsigned long long:   foo, \
    default:  bar)

If you have other cases than floating point, you may even go one step further

_Generic((e)+0ULL,             \
    unsigned long long:   foo, \
    default: _Generic((e)+0.0L,\
     long double:   bar,       \
     default:  blur))

This supposes that all your expressions e have arithmetic type. Remaining for the default in would then be _Complex types and all pointer types.

For the kind of usage you have in mind you should do such promotions, anyhow, because compilers currently interpret the controlling expression of _Generic differently. Some would also consider an object of type double const differently from double, for example. So this would really give you a lot of cases to consider, if you'd have to differentiate all possible type qualifications.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • The fact type promotion could be used in the example is unrelated to the actual question (not ideal examples then), edited the example. – ideasman42 Apr 26 '15 at 07:22