C++中如何通过预处理宏批量声明类及成员变量
实现可行性结论
可以通过标准C++预处理器可变参数宏实现你需要的批量类声明能力,不需要依赖编译器专属扩展,最终可以直接用你期望的NEW_CLASS(类名, 成员类型1, 成员名1, 成员类型2, 成员名2, ...)形式完成类定义。
具体实现代码
核心思路是通过预处理器参数计数宏,自动识别传入的成员数量,分发到对应参数个数的类模板展开分支,以下是可直接编译运行的完整实现:
#include <vector> // 基类定义,和业务场景保持一致 class ClassBase {}; // ------------------------------ 预处理器工具宏 ------------------------------ // 强制宏展开辅助 #define PP_EXPAND(x) x // 计算可变参数个数,默认支持最多8组成员(共16个可变参数,可按需扩展) #define PP_NARG(...) PP_EXPAND(PP_NARG_I(__VA_ARGS__, 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) #define PP_NARG_I(...) PP_EXPAND(PP_ARG_N(__VA_ARGS__)) #define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,N,...) N // 主入口宏 #define NEW_CLASS(ClassName, ...) \ PP_EXPAND(NEW_CLASS_I(ClassName, PP_NARG(__VA_ARGS__), __VA_ARGS__)) #define NEW_CLASS_I(ClassName, ArgCount, ...) \ PP_EXPAND(NEW_CLASS_DISPATCH(ClassName, ArgCount, __VA_ARGS__)) #define NEW_CLASS_DISPATCH(ClassName, ArgCount, ...) \ PP_EXPAND(NEW_CLASS_##ArgCount(ClassName, __VA_ARGS__)) // ------------------------------ 不同成员数的类展开模板 ------------------------------ // 1个成员 #define NEW_CLASS_2(ClassName, T1, m1) \ class ClassName : public ClassBase \ { \ public: \ T1 m1; \ std::vector<void*> fun() { \ return std::vector<void*>{&m1}; \ } \ }; // 2个成员 #define NEW_CLASS_4(ClassName, T1, m1, T2, m2) \ class ClassName : public ClassBase \ { \ public: \ T1 m1; \ T2 m2; \ std::vector<void*> fun() { \ return std::vector<void*>{&m1, &m2}; \ } \ }; // 3个成员,对应示例中的ClassA场景 #define NEW_CLASS_6(ClassName, T1, m1, T2, m2, T3, m3) \ class ClassName : public ClassBase \ { \ public: \ T1 m1; \ T2 m2; \ T3 m3; \ std::vector<void*> fun() { \ return std::vector<void*>{&m1, &m2, &m3}; \ } \ }; // 4个成员 #define NEW_CLASS_8(ClassName, T1, m1, T2, m2, T3, m3, T4, m4) \ class ClassName : public ClassBase \ { \ public: \ T1 m1; \ T2 m2; \ T3 m3; \ T4 m4; \ std::vector<void*> fun() { \ return std::vector<void*>{&m1, &m2, &m3, &m4}; \ } \ }; // 需要支持更多成员时,按上述规律继续添加NEW_CLASS_10、NEW_CLASS_12...分支即可
使用方式与展开效果
直接按照期望的语法声明类即可:
NEW_CLASS(ClassA, int, a, float, b, char, c)
通过GCC/Clang的-E参数或MSVC的/P参数查看预处理器展开结果,和手写的目标类完全一致:
class ClassA : public ClassBase { public: int a; float b; char c; std::vector<void *> fun() { std::vector<void *> v{&a, &b, &c}; return v; } };
补充说明
- 之前提到的
BEGIN_CLASS/MEMBER/END_CLASS分段宏方案不可行,核心原因是C++预处理器做文本替换时没有状态存储能力,无法在多次调用MEMBER宏时累积记录所有传入的成员信息,自然无法在END_CLASS阶段统一生成成员声明和函数逻辑。 - 上述可变参数宏方案完全遵循C++标准,没有编译器专属依赖。唯一的限制是需要预先定义好最大支持的成员数量,常规业务场景下扩展到支持16~32个成员足够覆盖绝大多数使用需求,扩展时仅需要按固定模式复制修改宏分支即可。
- 如果不想手动编写重复的宏分支,可以借助预处理器元编程库的序列遍历能力自动生成对应分支,核心逻辑和上述手动实现没有区别。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

