Oh well...
here's the beginning of a macro solution using the boost preprocessor library (C99-preprocessor-compliant).
The idea was to provide a generic syntax that allows writing nested generic selections for an arbitrary number of arguments. To keep it "simple", the expression to select is the same for all elements on the same level of selection (you could define another syntax to alter the controlling expression on each selection of a level individually..).
This example from OP
#define plop(a,b) _Generic((a,b), \
(int,long): plopii, \
(double,short int): plopdd)(a,b)
becomes
#define plop(a,b) \
MULT_GENERIC((a,b), \
(int, (long, plopii)), \
(double, (short int, plopdd)) \
)(a,b)
Although I guess one could alter it slightly to get something like:
#define plop(a,b) \
MULT_GENERIC((a,b), \
(int, long: plopii), \
(double, short int: plopdd) \
)(a,b)
Which could expand for three parameters to:
#define plop(a,b,c) \
MULT_GENERIC((a,b,c), \
(int, (double, long: plopidl, int: plopidi)), \
(double, (short int, long: plopdsl)) \
)(a,b)
A further comment: I think OP's syntax could be done as well, but it isn't as flexible, as you have to repeat the first argument for every possible second argument, e.g.
#define plop(a,b) _Generic((a,b), \
(int,long): plopii, \
(int,double): plobid \
(double,short int): plopdd)(a,b)
OP's example in my syntax. Note that you don't gain much here as you still have to specify each type specifically and in this case the second type several times for different first types.
#define pow(x, y) MULT_GENERIC( \
(x, y), \
(long double complex, (default, cpowl) \
), \
(double complex, (long double complex, cpowl) \
, (default, cpow) \
), \
(float complex, (long double complex, cpowl) \
, (double complex, cpow) \
, (default, cpowf) \
), \
(long double, (long double complex, cpowl) \
, (double complex, cpow) \
, (float complex, cpowf) \
, (default, powl) \
), \
(default, (long double complex, cpowl) \
, (double complex, cpow) \
, (float complex, cpowf) \
, (long double, powl) \
, (default, pow) \
), \
(float, (long double complex, cpowl) \
, (double complex, cpow) \
, (float complex, cpowf) \
, (long double, powl) \
, (float, powf) \
, (default, pow) \
) \
) \
(x, y)
pow(x, y)
This is resolved to:
_Generic( (x), long double complex : _Generic( (y), default : cpowl ) , double complex : _Generic( (y), long double complex : cpowl , default : cpow ) , float complex : _Generic( (y), long double complex : cpowl , double complex : cpow , default : cpowf ) , long double : _Generic( (y), long double complex : cpowl , double complex : cpow , float complex : cpowf , default : powl ) , default : _Generic( (y), long double complex : cpowl , double complex : cpow , float complex : cpowf , long double : powl , default : pow ) , float : _Generic( (y), long double complex : cpowl , double complex : cpow , float complex : cpowf , long double : powl , float : powf , default : pow ) ) (x, y)
Which is, reformatted:
_Generic((x),
long double complex: _Generic((y), default: cpowl)
, double complex: _Generic((y),
long double complex: cpowl
, default: cpow)
, float complex: _Generic((y),
long double complex: cpowl
, double complex: cpow
, default: cpowf)
, long double: _Generic((y),
long double complex: cpowl
, double complex: cpow
, float complex: cpowf
, default: powl)
, default: _Generic((y),
long double complex: cpowl
, double complex: cpow
, float complex: cpowf
, long double: powl
, default: pow)
, float: _Generic((y)
, long double complex: cpowl
, double complex: cpow
, float complex: cpowf
, long double: powl
, float : powf
, default: pow)
)
(x, y)
Because of the recursive nature, I had to introduce copies of macros; this solution also needs a clean-up (I'm a bit tired). The macros:
#include <boost/preprocessor.hpp>
#define MULT_GENERIC_GET_ASSOC_SEQ(DATA_TUPLE) \
BOOST_PP_TUPLE_ELEM(2, DATA_TUPLE)
#define MULT_GENERIC_NTH_ASSOC_TUPLE(N, DATA_TUPLE) \
BOOST_PP_SEQ_ELEM( N, MULT_GENERIC_GET_ASSOC_SEQ(DATA_TUPLE) )
#define MULT_GENERIC_GET_TYPENAME(N, DATA_TUPLE) \
BOOST_PP_TUPLE_ELEM(0, MULT_GENERIC_NTH_ASSOC_TUPLE(N, DATA_TUPLE))
#define MULT_GENERIC_GET_EXPR( N, DATA_TUPLE ) \
BOOST_PP_TUPLE_ELEM(1, MULT_GENERIC_NTH_ASSOC_TUPLE(N, DATA_TUPLE))
#define MULT_GENERIC_LEVEL_REP1(z, N, DATA_TUPLE) \
MULT_GENERIC_GET_TYPENAME( N, DATA_TUPLE ) \
: \
BOOST_PP_TUPLE_ELEM(1, DATA_TUPLE) /*LEVEL_MACRO*/ ( \
BOOST_PP_TUPLE_ELEM(0, DATA_TUPLE) /*SEL_EXPR_SEQ*/ \
, BOOST_PP_SEQ_POP_FRONT( BOOST_PP_TUPLE_TO_SEQ(MULT_GENERIC_NTH_ASSOC_TUPLE(N, DATA_TUPLE)) ) \
)
#define MULT_GENERIC_LEVEL1(SEL_EXPR_SEQ, LEVEL_MACRO, ASSOC_SEQ) \
_Generic( \
(BOOST_PP_SEQ_HEAD(SEL_EXPR_SEQ)), \
BOOST_PP_ENUM( BOOST_PP_SEQ_SIZE(ASSOC_SEQ), MULT_GENERIC_LEVEL_REP1, (BOOST_PP_SEQ_POP_FRONT(SEL_EXPR_SEQ), LEVEL_MACRO, ASSOC_SEQ) ) \
)
#define MULT_GENERIC_LEVEL_REP2(z, N, DATA_TUPLE) \
MULT_GENERIC_GET_TYPENAME( N, DATA_TUPLE ) \
: \
BOOST_PP_TUPLE_ELEM(1, DATA_TUPLE) /*LEVEL_MACRO*/ ( \
BOOST_PP_TUPLE_ELEM(0, DATA_TUPLE) /*SEL_EXPR_SEQ*/ \
, BOOST_PP_SEQ_POP_FRONT( BOOST_PP_TUPLE_TO_SEQ(MULT_GENERIC_NTH_ASSOC_TUPLE(N, DATA_TUPLE)) ) \
)
#define MULT_GENERIC_LEVEL2(SEL_EXPR_SEQ, LEVEL_MACRO, ASSOC_SEQ) \
_Generic( \
(BOOST_PP_SEQ_HEAD(SEL_EXPR_SEQ)), \
BOOST_PP_ENUM( BOOST_PP_SEQ_SIZE(ASSOC_SEQ), MULT_GENERIC_LEVEL_REP2, (BOOST_PP_SEQ_POP_FRONT(SEL_EXPR_SEQ), LEVEL_MACRO, ASSOC_SEQ) ) \
)
#define MULT_GENERIC0(SEL_EXPR_SEQ, ASSOC_SEQ) \
BOOST_PP_SEQ_HEAD(ASSOC_SEQ)
#define MULT_GENERIC1(SEL_EXPR_SEQ, ASSOC_SEQ) \
MULT_GENERIC_LEVEL1( SEL_EXPR_SEQ, MULT_GENERIC0, ASSOC_SEQ )
#define MULT_GENERIC2(SEL_EXPR_SEQ, ASSOC_SEQ) \
MULT_GENERIC_LEVEL2( SEL_EXPR_SEQ, MULT_GENERIC1, ASSOC_SEQ )
#define MULT_GENERIC(SEL_EXPR_TUPLE, ...) \
BOOST_PP_CAT(MULT_GENERIC, BOOST_PP_TUPLE_SIZE(SEL_EXPR_TUPLE)) ( BOOST_PP_TUPLE_TO_SEQ(SEL_EXPR_TUPLE), BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__)) )