cpp foreach macro
showcase
- EqualToAnyOf
// 注意 递归单元 EqualToAnyOf(3, 1, 2, 3); // 0 || (3 == 1) || (3 == 2) || (3 == 3) - MAKE_ENUM
MAKE_ENUM(EE,"name_prefix",E1,E2,E3); // 展开到 enum class EE {E1, E2,E3 }; const char *GetStr(EE e) {g switch (e) { case EE::E1: return "name_prefix" "E1"; case EE::E2: return "name_prefix" "E2"; case EE::E3: return "name_prefix" "E3"; default: return "name_prefix" ""; } };
介绍
// prototype
#define FOREACH(pps,...) ...
// acutually params
#define FOREACH(pps,it_operator,...)
pps: 打包参数,形如 (arg1), (arg1,arg2)
it_operator: 迭代宏函数,如此使用:ite_operator(pps,it)
...: 迭代参数集合,展开后作为 ite_oprator的最后一个参数
实现
辅助宏函数
-
__Choose20th
#define __Choose20th(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13,_14, _15, _16, _17, _18, _19, _20, ...) \ _20 -
ID
msvc默认的宏展开有一点区别于gcc like编译器,所以老是需要用ID去做展开#define ID(_1, ...) _1 #define IDx(...) __VA_ARGS__ -
Callx+CallxPPS#define Callx(f, ...) IDx(f(__VA_ARGS__)) #define CallxPPS(f, _1) IDx(f _1)两种形式的宏函数代理调用
因为当我遇到MacroFunc(IDx pps, otherArgs)时,外部套一层IDx也无法使展开的pps作为分离参数传入MacroFunc感觉 ID只能辅助展开
__VA_ARGS__,所以这里Callx(MacroFunc, IDx pps, otherArgs)将所有参数压缩成变长参数之后再由Callx重新展开
过程
OK, finally.
Show me the code
#define __Choose20th(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, ...) _20
#define ID(_1, ...) _1
#define IDx(...) __VA_ARGS__
#define Callx(f, ...) IDx(f(__VA_ARGS__))
#define CallxPPS(f, _1) IDx(f _1)
#define FOREACH0(it_operator, pps)
#define FOREACH1(it_operator, pps, _1) IDx(it_operator(pps, _1) FOREACH0(it_operator, pps))
#define FOREACH2(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH1(it_operator, pps, __VA_ARGS__))
#define FOREACH3(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH2(it_operator, pps, __VA_ARGS__))
#define FOREACH4(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH3(it_operator, pps, __VA_ARGS__))
#define FOREACH5(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH4(it_operator, pps, __VA_ARGS__))
#define FOREACH6(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH5(it_operator, pps, __VA_ARGS__))
#define FOREACH7(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH6(it_operator, pps, __VA_ARGS__))
#define FOREACH8(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH7(it_operator, pps, __VA_ARGS__))
#define FOREACH9(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH8(it_operator, pps, __VA_ARGS__))
#define FOREACH10(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH9(it_operator, pps, __VA_ARGS__))
#define FOREACH11(it_operator, pps, _1, ...) IDx(it_operator(pps, _1) FOREACH10(it_operator, pps, __VA_ARGS__))
#define FOREACH(pps, ...) \
ID(__Choose30th(__VA_ARGS__, \
FOREACH28, FOREACH27, FOREACH26, FOREACH25, FOREACH24, FOREACH23, FOREACH22, FOREACH21, FOREACH20, FOREACH19, FOREACH18, FOREACH17, FOREACH16, FOREACH15, FOREACH14, FOREACH13, FOREACH12, FOREACH11, FOREACH10, FOREACH9, FOREACH8, FOREACH7, FOREACH6, FOREACH5, FOREACH4, FOREACH3, FOREACH2, FOREACH1, FOREACH0)) \
IDx((pps, __VA_ARGS__))
Use Case
EqualToAnyOf
#define __EqualToPlain(x, y) || (x == y)
#define __EqualToPacket(px, y) Callx(__EqualToPlain, IDx px, y)
#define EqualToAnyOf(val, ...) 0 FOREACH(__EqualToPacket, (val), __VA_ARGS__)
MAKE_ENUM
#define MAKE_ENUM_Declare(ClsName,...) enum class ClsName{__VA_ARGS__};
#define MAKE_ENUM_ITEM_Begin(ClsName) \
const char *GetStr(ClsName e) \
{ \
switch (e) \
{
#define MAKE_ENUM_ITEM(ClsName, Prefix, name) \
case ClsName::name: \
return Prefix #name;
// #define MAKE_ENUM_ITEM_PPS(pps, item) CallxPPS( Callx,(MAKE_ENUM_ITEM, IDx pps, item))
#define MAKE_ENUM_ITEM_PPS(pps, item) Callx(MAKE_ENUM_ITEM, IDx pps, item)
#define MAKE_ENUM_ITEM_End(ClsName, Prefix) \
default: \
return Prefix ""; \
} \
}
#define MAKE_ENUM(ClsName, Prefix, ...) \
MAKE_ENUM_Declare(ClsName, __VA_ARGS__) \
MAKE_ENUM_ITEM_Begin(ClsName) \
IDx(FOREACH(MAKE_ENUM_ITEM_PPS, (ClsName, Prefix), __VA_ARGS__)) \
MAKE_ENUM_ITEM_End(ClsName, Prefix);
附录
- 检查 预处理器输出
即使是vs2022默认的智能感知引擎也无法在hover tip上正确显示预处理的结果,所以需要手动用编译器展开观察中间结果
# MSVC >> foreach_macro.i
while($true)
{
cl /P foreach_macro.cpp
sleep 1
}
# CLANG >> stdout (or append "-o foreach_macro.i")
while($true)
{
clang -E foreach_macro.cpp
sleep 1
}
浙公网安备 33010602011771号