如何减少C++函数指针接口的透传方法样板代码
解决方案:用C++17特性自动生成透传函数指针
由于你无法修改全局变量gClass和函数指针结构体的要求,我们可以利用C++17的auto模板参数和无捕获lambda来自动生成透传包装器,彻底消除手写样板代码的需求。
步骤1:编写通用包装器生成函数
这个函数会根据传入的成员函数指针,自动生成匹配接口签名的函数指针:
#include <type_traits> #include <utility> // 保留你无法修改的全局变量声明 extern MyImplementingClass* gClass; template <auto MemFunc> constexpr auto make_interface_wrapper() { // 无捕获lambda可隐式转换为C函数指针,内部直接转发调用给gClass的成员函数 return +[](auto&&... args) -> std::invoke_result_t<decltype(MemFunc), MyImplementingClass*, decltype(args)...> { if constexpr (std::is_void_v<std::invoke_result_t<decltype(MemFunc), MyImplementingClass*, decltype(args)...>>) { (gClass->*MemFunc)(std::forward<decltype(args)>(args)...); } else { return (gClass->*MemFunc)(std::forward<decltype(args)>(args)...); } }; }
步骤2:简化接口填充代码
现在你不需要手写每个全局透传函数,直接调用包装器生成函数填充接口:
void populateInterface(PluginInterface& iface) { iface.method1 = make_interface_wrapper<&MyImplementingClass::method1>(); iface.method2 = make_interface_wrapper<&MyImplementingClass::method2>(); iface.method3 = make_interface_wrapper<&MyImplementingClass::method3>(); // 其他方法依此类推 }
可选:用宏进一步简化书写
如果觉得make_interface_wrapper<&...>()的写法繁琐,可以定义一个宏:
#define WRAP_CLASS_METHOD(func) make_interface_wrapper<&MyImplementingClass::func>()
然后填充接口时可以写成:
void populateInterface(PluginInterface& iface) { iface.method1 = WRAP_CLASS_METHOD(method1); iface.method2 = WRAP_CLASS_METHOD(method2); iface.method3 = WRAP_CLASS_METHOD(method3); }
方案核心原理
- 无捕获lambda转函数指针:C++11及以后允许无捕获lambda隐式转换为C兼容的函数指针,完全符合接口的函数指针要求。
- auto模板参数推导:C++17的auto模板参数可以直接推导成员函数指针的类型,无需手动编写多个特化版本。
- 参数转发正确性:
std::forward保证了参数(包括引用类型,比如method3的const int&)被正确转发到成员函数。 - 编译期检查:如果成员函数签名和接口函数指针不匹配,编译器会直接报错,提前发现问题。
内容的提问来源于stack exchange,提问作者Dean
相关产品推荐
相关产品推荐

