ideasman42
ideasman42

Reputation: 48058

_Generic: multiple types to a single value?

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)

Upvotes: 1

Views: 782

Answers (2)

Jens Gustedt
Jens Gustedt

Reputation: 78923

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.

Upvotes: 3

Jens Gustedt
Jens Gustedt

Reputation: 78923

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.

Upvotes: 0

Related Questions