哦,好吧...这是使用 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__)) )