您可以使用X Macros。通过在可重新定义的宏中定义包含重复值表的单个宏,您只需为当前任务重新定义内部宏并插入单个宏来处理整个集合。
这里有一个简洁的方法,以单操作数浮点内置函数为例。其他类型的过程类似。
//add name of each function you want to use here:
#define UNARYFPBUILTINS \
$(acos) $(acosh) $(asin) $(asinh) $(atan) $(atanh) $(cbrt) $(ceil) \
$(cos) $(erf) $(erfc) $(exp) $(exp10) $(exp2) $(expm1) $(fabs) \
$(floor) $(gamma) $(j0) $(j1) $(lgamma) $(log) $(log10) $(log1p) \
$(log2) $(logb) $(pow10) $(round) $(signbit) $(significand) \
$(sin) $(sqrt) $(tan) $(tgamma) $(trunc) $(y0) $(y1)
//now define the $(x) macro for our current use case - defining enums
#define $(x) UFPOP_##x,
enum ufp_enum{ UNARYFPBUILTINS };
#undef $ //undefine the $(x) macro so we can reuse it
//feel free to remove the __builtin_## ... its just an optimization
double op(enum ufp_enum op, double f){
switch(op){ //now we can use the same macros for our cases
#define $(x) case UFPOP_##x : f = __builtin_##x(f);break;
UNARYFPBUILTINS
#undef $
}
return f;
}
你也可以继续使用它来做其他事情
///////////EXTRA STUFF/////////
//unused - may be good mapping the enums to strings
//#define $(x) #x,
//const char * ufp_strings{ UNARYFPBUILTINS };
//#undef $
//this uses float instead of double, so adds the ##f to each function
float opf(enum ufp_enum op, float f){
switch(op){
#define $(x) case UFPOP_##x : f = __builtin_##x##f(f);break;
UNARYFPBUILTINS
#undef $
}
return f;
}
//you could do the same thing for long double here
编辑:注意宏中的 $ 是依赖于实现的,你可以随便调用它
Edit2:这是一个使用多个参数来执行算术运算符的示例。这个使用计算的 goto 而不是 switch,以防你的编译器处理一个比另一个更好。
#define IOPS $(SUB,-) $(MUL,*) $(DIV,/) $(MOD,%) $(ADD,+) $(AND,&) $(OR,|) \
$(XOR,^) $(SR,>>) $(SL,<<)
enum iops_enum {
#define $(x,op) IOPSENUM_##x,
IOPS
IOPSENUM_COUNT
#undef $
};
int opi(int a, enum iops_enum b, int c){
static const char array[] = { //you may get better results with short or int
#define $(x,op) &&x - &&ADD,
IOPS
#undef $
};
if (b >= IOPSENUM_COUNT) return a;
goto *(&&ADD + array[b]);
//else should give a warning here.
#define $(x,op) x: return a op c;
IOPS
#undef $
}