C11中多参数C函数的泛型

C11中多参数C函数的泛型,c,c11,C,C11,我了解单参数函数的C11泛型,如:(from) 但是,对于具有两个参数的函数来说,这似乎是一个难题,您需要嵌套对\u Generic的调用,这真的很难看;摘自同一博客: #define pow(x, y) _Generic((x), \ long double complex: cpowl, \ double complex: _Generic((y), \ long double complex: cpowl, \ default: cpow), \ float complex: _Gen

我了解单参数函数的C11泛型,如:(from)

但是,对于具有两个参数的函数来说,这似乎是一个难题,您需要嵌套对
\u Generic
的调用,这真的很难看;摘自同一博客:

#define pow(x, y) _Generic((x), \
long double complex: 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)
有没有一种方法可以为多参数函数提供更多人类可读的泛型,例如:

#define plop(a,b) _Generic((a,b), \
      (int,long): plopii, \
      (double,short int): plopdd)(a,b)

提前感谢您的回复。基本思想是为
\u Generic

提供一个宏包装器,因为
\u Generic
的控制表达式没有计算,我建议应用一些算术运算,进行适当的类型组合,并打开结果。因此:

#define OP(x, y) _Generic((x) + (y), \
    long double complex: LDC_OP(x, y), \
    double complex: DC_OP(x, y), \
    ... )

当然,这只适用于某些情况,但您始终可以展开“折叠”类型没有帮助的情况。(这将使我们能够处理字符的数组N与
char*
,例如,与链接的
printnl
示例一样,然后如果组合类型为
int
,我们可以返回并检查
char
short

既然C没有元组,让我们制作自己的元组:

typedef struct {int _;} T_double_double;
typedef struct {int _;} T_double_int;
typedef struct {int _;} T_int_double;
typedef struct {int _;} T_int_int;

typedef struct { T_double_double Double; T_double_int Int;} T_double;
typedef struct { T_int_double Double;    T_int_int    Int;} T_int;

#define typeof1(X)       \
_Generic( (X),            \
    int:    (T_int){{0}},  \
    double: (T_double){{0}} )

#define typeof2(X, Y)      \
_Generic( (Y),              \
    int:    typeof1(X).Int,  \
    double: typeof1(X).Double )
这是客户端代码:

#include <stdio.h>
#include "generics.h"

#define typename(X, Y)               \
_Generic( typeof2(X, Y),              \
    T_int_int: "int, int\n",           \
    T_int_double: "int, double\n",      \
    T_double_double: "double, double\n", \
    T_double_int: "double, int\n",        \
    default: "Something else\n"            )

int main() {
    printf(typename(1, 2));
    printf(typename(1, 2.0));
    printf(typename(1.0, 2.0));
    printf(typename(1.0, 2));
    return 0;
}
是的,您仍然需要以指数大小编写代码。但至少你可以重新使用它。

哦,好吧。。。 下面是使用boost预处理器库(C99预处理器兼容)的宏解决方案的开始

其思想是提供一种通用语法,允许为任意数量的参数编写嵌套的通用选择。为了保持“简单”,要选择的表达式对于同一选择级别上的所有元素都是相同的(您可以定义另一种语法来分别更改级别的每个选择上的控制表达式…)


这个例子来自OP

#define plop(a,b) _Generic((a,b), \
  (int,long): plopii, \
  (double,short int): plopdd)(a,b)
变成

#define plop(a,b)                  \
  MULT_GENERIC((a,b),              \
    (int, (long, plopii)),         \
    (double, (short int, plopdd))  \
  )(a,b)
虽然我想可以稍微修改一下,得到如下结果:

#define plop(a,b)                  \
  MULT_GENERIC((a,b),              \
    (int, long: plopii),           \
    (double, short int: plopdd)    \
  )(a,b)
它可以扩展为三个参数:

#define plop(a,b,c)                                \
  MULT_GENERIC((a,b,c),                            \
    (int, (double, long: plopidl, int: plopidi)),  \
    (double, (short int, long: plopdsl))           \
  )(a,b)
进一步的评论:我认为OP的语法也可以这样做,但它没有那么灵活,因为你必须为每一个可能的第二个参数重复第一个参数,例如

#define plop(a,b) _Generic((a,b), \
  (int,long): plopii, \
  (int,double): plobid \
  (double,short int): plopdd)(a,b)

我的语法中的OP示例。请注意,您在这里并没有获得太多的收益,因为您仍然需要专门指定每种类型,在本例中,第二种类型会针对不同的第一种类型多次指定

#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)
决议如下:

_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)
也就是说,重新格式化:

_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)
由于递归性,我不得不引入宏的副本;这个解决方案也需要清理(我有点累)。宏:

#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__)) )
#包括
#定义多个通用获取关联顺序(数据元组)\
BOOST\u PP\u TUPLE\u ELEM(2,数据组)
#定义多个通用关联元组(N,数据元组)\
BOOST\u PP\u SEQ\u ELEM(N,多个通用\u GET\u ASSOC\u SEQ(数据元组))
#定义多个泛型获取类型名(N,数据元组)\
BOOST\u PP\u TUPLE\u ELEM(0,多个通用\u N个关联\u TUPLE(N,数据\u TUPLE))
#定义多泛型获取表达式(N,数据元组)\
BOOST\u PP\u TUPLE\u ELEM(1,多个通用\u N个关联\u TUPLE(N,数据\u TUPLE))
#定义多个通用级REP1(z,N,数据元组)\
多泛型获取类型名(N,数据元组)\
: \
BOOST_PP_TUPLE_ELEM(1,数据_TUPLE)/*LEVEL_MACRO*/(\
BOOST\u PP\u TUPLE\u ELEM(0,数据组)/*SEL\u EXPR\u SEQ*/\
,BOOST_PP_SEQ_POP_FRONT(BOOST_PP_TUPLE_TO SEQ(MULT_GENERIC_NTH_ASSOC_TUPLE(N,DATA_TUPLE)))\
)
#定义多个通用级别1(选择扩展顺序、级别宏、关联顺序)\
_通用(\
(增压泵头(选择出口顺序))\
BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(ASSOC_SEQ)、多个通用级_LEVEL_REP1、(BOOST_PP_SEQ_POP_FRONT(SEL_EXPR SEQ)、LEVEL_MACRO、ASSOC_SEQ))\
)
#定义多个通用级REP2(z,N,数据元组)\
多泛型获取类型名(N,数据元组)\
: \
BOOST_PP_TUPLE_ELEM(1,数据_TUPLE)/*LEVEL_MACRO*/(\
BOOST\u PP\u TUPLE\u ELEM(0,数据组)/*SEL\u EXPR\u SEQ*/\
,BOOST_PP_SEQ_POP_FRONT(BOOST_PP_TUPLE_TO SEQ(MULT_GENERIC_NTH_ASSOC_TUPLE(N,DATA_TUPLE)))\
)
#定义多个通用级别2(选择扩展顺序、级别宏、关联顺序)\
_通用(\
(增压泵头(选择出口顺序))\
BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(ASSOC_SEQ),多个通用级_LEVEL_REP2,(BOOST_PP_SEQ_POP_FRONT(SEL_EXPR SEQ),LEVEL_MACRO,ASSOC_SEQ))\
)
#定义多个通用0(选择表达式顺序、关联顺序)\
增压头(助理)
#定义多个通用1(选择扩展顺序、关联顺序)\
多个通用级别1(选择扩展顺序、多个通用级别0、助理顺序)
#定义多个通用2(选择扩展顺序、关联顺序)\
多个通用级别2(选择扩展顺序、多个通用级别1、助理顺序)
#定义多泛型(选择表达式元组,…)\
BOOST_PP_CAT(多个通用、BOOST_PP_TUPLE_SIZE(SEL_EXPR_TUPLE))(BOOST_PP_TUPLE_TO SEQ(SEL_EXPR_TUPLE)、BOOST_PP_TUPLE_TO SEQ(((()

这是一个只需要手工编写线性代码的版本,所有这些代码都与手头的事情直接相关(没有手工定义类型的大型树)。首先,使用示例:

#include <stdio.h>

// implementations of print
void print_ii(int a, int b) { printf("int, int\n"); }
void print_id(int a, double b) { printf("int, double\n"); }
void print_di(double a, int b) { printf("double, int\n"); }
void print_dd(double a, double b) { printf("double, double\n"); }
void print_iii(int a, int b, int c) { printf("int, int, int\n"); }
void print_default(void) { printf("unknown arguments\n"); }

// declare as overloaded
#define print(...) OVERLOAD(print, (__VA_ARGS__), \
    (print_ii, (int, int)), \
    (print_id, (int, double)), \
    (print_di, (double, int)), \
    (print_dd, (double, double)), \
    (print_iii, (int, int, int)) \
)


#define OVERLOAD_ARG_TYPES (int, double)
#define OVERLOAD_FUNCTIONS (print)


#include "activate-overloads.h"


int main(void) {
    print(44, 47);   // prints "int, int"
    print(4.4, 47);  // prints "double, int"
    print(1, 2, 3);  // prints "int, int, int"
    print("");       // prints "unknown arguments"
}
这需要Vesa K.的真棒

它的实际工作方式:使用
重载\u ARG\u类型
声明构建一个枚举,列出作为常量使用的所有参数类型。然后,调用方代码中对重载名称的每个调用都可以被所有实现(正确的参数号)之间的大型三元操作调度所取代。分派的工作原理是使用
\u Generic
从参数类型生成枚举值,将这些值放入数组中,并使用自动生成的分派器函数返回该类型组合的ID(原始块中的位置)。如果ID匹配,则调用该函数。如果参数的类型错误,则会为未使用的实现调用生成伪值,以避免类型不匹配

从技术上讲,这涉及到一个“运行时”调度,但由于每种类型
#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__)) )
#include <stdio.h>

// implementations of print
void print_ii(int a, int b) { printf("int, int\n"); }
void print_id(int a, double b) { printf("int, double\n"); }
void print_di(double a, int b) { printf("double, int\n"); }
void print_dd(double a, double b) { printf("double, double\n"); }
void print_iii(int a, int b, int c) { printf("int, int, int\n"); }
void print_default(void) { printf("unknown arguments\n"); }

// declare as overloaded
#define print(...) OVERLOAD(print, (__VA_ARGS__), \
    (print_ii, (int, int)), \
    (print_id, (int, double)), \
    (print_di, (double, int)), \
    (print_dd, (double, double)), \
    (print_iii, (int, int, int)) \
)


#define OVERLOAD_ARG_TYPES (int, double)
#define OVERLOAD_FUNCTIONS (print)


#include "activate-overloads.h"


int main(void) {
    print(44, 47);   // prints "int, int"
    print(4.4, 47);  // prints "double, int"
    print(1, 2, 3);  // prints "int, int, int"
    print("");       // prints "unknown arguments"
}
// activate-overloads.h
#include <order/interpreter.h>

#define ORDER_PP_DEF_8dispatch_overload ORDER_PP_FN( \
8fn(8N, 8V, \
    8do( \
        8print( 8cat(8(static inline int DISPATCH_OVER_), 8N) ((int ac, int av[]) { return ) ), \
        8seq_for_each_with_idx( \
            8fn(8I, 8T, \
                8let( (8S, 8tuple_to_seq(8tuple_at_1(8T))), \
                    8print( 8lparen (ac==) 8to_lit(8seq_size(8S)) ), \
                    8seq_for_each_with_idx(8fn(8I, 8T, 8print( (&&av[) 8I (]==) 8cat(8(K_), 8T) )), 0, 8S), \
                    8print( 8rparen (?) 8I (:) ) \
                )), \
            1, 8V), \
        8print( ( -1; }) ) \
    ) ))

#define TYPES_TO_ENUMS(TS) ORDER_PP ( \
    8do( \
        8seq_for_each(8fn(8T, 8print( 8T (:) 8cat(8(K_), 8T) (,) )), \
                      8tuple_to_seq(8(TS))), \
        8print( (default: -1) ) \
    ) \
)
#define ENUMERATE_TYPES(TS) enum OVERLOAD_TYPEK { ORDER_PP ( \
    8seq_for_each(8fn(8V, 8print( 8V (,) )), 8types_to_vals(8tuple_to_seq(8(TS)))) \
) };
#define ORDER_PP_DEF_8types_to_vals ORDER_PP_FN( \
8fn(8S, 8seq_map(8fn(8T, 8cat(8(K_), 8T)), 8S)) )


ENUMERATE_TYPES(OVERLOAD_ARG_TYPES)
#define OVER_ARG_TYPE(V) _Generic((V), TYPES_TO_ENUMS(OVERLOAD_ARG_TYPES) )

#define OVERLOAD
ORDER_PP (
    8seq_for_each(
        8fn(8F,
            8lets( (8D, 8expand(8adjoin( 8F, 8(()) )))
                   (8O, 8seq_drop(2, 8tuple_to_seq(8D))),
                8dispatch_overload(8F, 8O) )),
        8tuple_to_seq(8(OVERLOAD_FUNCTIONS))
    )
)
#undef OVERLOAD

#define OVERLOAD(N, ARGS, ...) ORDER_PP ( \
    8do( \
        8print(8lparen), \
        8seq_for_each_with_idx( \
            8fn(8I, 8T, \
                8lets( (8S, 8tuple_to_seq(8tuple_at_1(8T))) \
                       (8R, 8tuple_to_seq(8(ARGS))) \
                       (8N, 8tuple_at_0(8T)), \
                    8if(8equal(8seq_size(8S), 8seq_size(8R)), \
                        8do( \
                            8print( 8lparen (DISPATCH_OVER_##N) 8lparen 8to_lit(8seq_size(8R)) (,(int[]){) ), \
                            8seq_for_each(8fn(8A, 8print( (OVER_ARG_TYPE) 8lparen 8A 8rparen (,) )), 8R), \
                            8print( (-1}) 8rparen (==) 8I 8rparen (?) 8N 8lparen ), \
                            8let( (8P, 8fn(8A, 8T, \
                                           8print( (_Generic) 8lparen 8lparen 8A 8rparen (,) 8T (:) 8A (,default:*) 8lparen 8T (*) 8rparen (0) 8rparen ) \
                                           )), \
                                8ap(8P, 8seq_head(8R), 8seq_head(8S)), \
                                8seq_pair_with(8fn(8A, 8T, 8do(8print((,)), 8ap(8P, 8A, 8T))), 8seq_tail(8R), 8seq_tail(8S)) \
                            ), \
                            8print( 8rparen (:) ) \
                        ), \
                        8print(( )) ) \
                )), \
            1, 8tuple_to_seq(8((__VA_ARGS__))) \
        ), \
        8print( 8cat(8(N), 8(_default)) (()) 8rparen) \
    ) \
)
#include<stdio.h>

double multiply_id ( int a, double b )
{
    return a * b;
}

double multiply_di ( double a, int b )
{
    return a * b;
}

double multiply_dd ( double a, double b )
{
    return a * b;
}

int multiply_ii ( int a, int b )
{
    return a * b;
}


/*
#define multiply(a,b) _Generic((a), \
int: _Generic((b), \
    int: multiply_ii, \
    double: multiply_id), \
double: _Generic((b), \
    int: multiply_di, \
    double: multiply_dd) ) (a,b)
*/

#define _G2(ParamB,ParamA_Type, TypeB1, TypeB1_Func, TypeB2, TypeB2_Func) \
    ParamA_Type: _Generic((ParamB), \
        TypeB1: TypeB1_Func, \
        TypeB2: TypeB2_Func)

#define multiply(a,b) _Generic((a), \
    _G2(b,int,int,multiply_ii,double,multiply_id), \
    _G2(b,double,int,multiply_di,double,multiply_dd) ) (a,b)


int main(int argc, const char * argv[]) {
    int i;
    double d;

    i = 5;
    d = 5.5;

    d = multiply( multiply(d, multiply(d,i) ) ,multiply(i,i) );

    printf("%f\n", d);  
    return 0;
}