如何在C++ JSONDUMP宏中仅通过名称引用调用成员函数?
解决方案:结合C++编译时特性实现统一的字段/方法序列化
纯预处理器没法区分成员变量和成员函数,得结合C++的模板重载或者编译时判断来实现你要的效果,下面给两种可行的方案:
方案一:C++11兼容的模板重载法
这个方法靠重载辅助函数,自动适配成员变量和无参const成员函数:
1. 定义辅助函数和宏
#include <utility> // 处理成员变量的重载 template<typename T, typename Class> auto dump_helper(const Class* obj, T Class::*member) -> decltype(obj->*member) { return obj->*member; } // 处理无参const成员函数的重载 template<typename Ret, typename Class> auto dump_helper(const Class* obj, Ret (Class::*func)() const) -> Ret { return (obj->*func)(); } // 封装成字段宏 #define JSON_FIELD(name) #name, dump_helper(this, &decltype(*this)::name) // 你的JSONDUMP宏改造 #define JSONDUMP(...) \ JSONObject jsonDump() const { \ return JSONObject{ __VA_ARGS__ }; \ }
2. 使用示例
class MyClass { private: int m_size; int len() const { return m_size * 2; } public: JSONDUMP( JSON_FIELD(m_size), // 成员变量直接用名称 JSON_FIELD(len) // 成员函数也直接用名称,无需加() ); };
工作原理:JSON_FIELD(name)会把名称转换成类成员的指针(&MyClass::name),然后根据这个指针是成员变量指针还是成员函数指针,匹配对应的dump_helper重载,自动完成取值或调用。
方案二:C++17的if constexpr简洁法
如果你的项目可以用C++17,用编译时判断会更简洁,不需要写多个重载:
1. 定义宏
#include <type_traits> #define JSONDUMP(...) \ JSONObject jsonDump() const { \ auto get_value = [this](auto mem) { \ // 编译时判断:如果是可调用的成员函数,就调用;否则取成员变量 if constexpr (std::is_invocable_r_v<decltype((this->*mem)()), const decltype(*this)&>) { return (this->*mem)(); } else { return this->*mem; } }; \ return JSONObject{ __VA_ARGS__ }; \ } #define JSON_FIELD(name) #name, get_value(&decltype(*this)::name)
2. 使用方式和方案一完全相同
这个方法靠if constexpr在编译时分支处理,代码更紧凑,可读性更好。
注意事项
- 这两个方案都只支持无参的const成员函数,如果要支持带参数的函数或者非const函数,需要扩展对应的重载/判断逻辑。
- 纯预处理器无法实现这个需求,因为预处理器只做文本替换,不知道符号的类型信息,必须依赖C++的编译时类型检查能力。
内容的提问来源于stack exchange,提问作者Manu343726
相关产品推荐
相关产品推荐

