如何用C++元编程实现类似mem_fn的工具,将成员函数转为C风格函数指针
解决方案
实现思路
通过模板自动萃取类成员函数的返回值、所属类、参数列表,生成符合要求的无捕获lambda作为适配层,无捕获lambda可以直接转换为对应签名的C风格函数指针,无需手动为每个成员函数编写适配代码。
通用适配代码
#include <utility> // 适配普通非const成员函数 template <typename Ret, typename Class, typename... Args> constexpr auto make_c_adapter(Ret(Class::*mem_func)(Args...)) { // 无捕获lambda可以隐式转换为C函数指针,+号强制触发转换 return +[](void* data, Args... args) -> Ret { Class* instance = static_cast<Class*>(data); return (instance->*mem_func)(std::forward<Args>(args)...); }; } // 适配const成员函数,按需增加 template <typename Ret, typename Class, typename... Args> constexpr auto make_c_adapter(Ret(Class::*mem_func)(Args...) const) { return +[](void* data, Args... args) -> Ret { const Class* instance = static_cast<const Class*>(data); return (instance->*mem_func)(std::forward<Args>(args)...); }; }
使用示例
修改原有代码的main函数即可直接使用:
int main() { // 原有写法可正常保留 regisAdd(doAdd); callAdd(); regisAdd([](void* data, int a, int b) { return static_cast<ABC*>(data)->add(a, b); }); callAdd(); // 通用适配写法,无需手动编写适配函数 regisAdd(make_c_adapter(&ABC::add)); callAdd(); regisOther(make_c_adapter(&ABC::other)); callOther(); return 0; }
原理解释
- 模板会根据传入的成员函数指针自动推导所有类型参数,不需要手动指定模板实参
- 无捕获lambda前面加
+是强制触发lambda到函数指针的转换,保证返回值就是C风格函数指针类型 - 每个不同的成员函数指针都会实例化独立的模板,对应的lambda也是独立的,不会出现地址冲突
- 该实现兼容C++11及以上标准,不需要依赖任何第三方库
内容的提问来源于stack exchange,提问作者0xFFFFFFFF
相关产品推荐
相关产品推荐

