If a selection on multiple arguments for a type generic expression is wanted, and all types in question are arithmetic types, an easy way to avoid nested _Generic
expressions is to use addition of the parameters in the controlling expression:
int max_int(int, int);
unsigned max_unsigned(unsigned, unsigned);
double max_double(double, double);
#define MAX(X, Y) _Generic((X)+(Y), \
int: max_int, \
unsigned: max_unsigned, \
default: max_double) \
((X), (Y))
Here, the controlling expression (X)+(Y)
is only inspected according to its type and not evaluated. The usual conversions for arithmetic operands are performed to determine the selected type.
For more complex situation, a selection can be made based on more than one argument to the operator, by nesting them together.
This example selects between four externally implemented functions, that take combinations of two int and/or string arguments, and return their sum.
int AddIntInt(int a, int b);
int AddIntStr(int a, const char* b);
int AddStrInt(const char* a, int b );
int AddStrStr(const char* a, const char* b);
#define AddStr(y) \
_Generic((y), int: AddStrInt, \
char*: AddStrStr, \
const char*: AddStrStr )
#define AddInt(y) \
_Generic((y), int: AddIntInt, \
char*: AddIntStr, \
const char*: AddIntStr )
#define Add(x, y) \
_Generic((x) , int: AddInt(y) , \
char*: AddStr(y) , \
const char*: AddStr(y)) \
((x), (y))
int main( void )
{
int result = 0;
result = Add( 100 , 999 );
result = Add( 100 , "999" );
result = Add( "100" , 999 );
result = Add( "100" , "999" );
const int a = -123;
char b[] = "4321";
result = Add( a , b );
int c = 1;
const char d[] = "0";
result = Add( d , ++c );
}
Even though it appears as if argument y
is evaluated more than once, it isn't 1. Both arguments are evaluated only once, at the end of macro Add: ( x , y )
, just like in an ordinary function call.
1 (Quoted from: ISO:IEC 9899:201X 6.5.1.1 Generic selection 3)
The controlling expression of a generic selection is not evaluated.