基于SWIG实现C++调用多回调:std::function方案可行性及director适用性问询
问题描述
近期我开始使用SWIG开发解决方案,需向C层传递若干回调函数并在该层调用。我已通过继承C层基类的方式实现需求,但希望改用std::function实例替代类指针传递回调。以下是我设想的示例代码(目前无法正常运行):
File example.h
#include <functional> #include <map> #include <vector> class Controller { private: std::vector<std::function<void()>> functions; public: virtual void AddFunction(const std::function<void(void)>& func) { functions.push_back(func); } virtual void Execute() { for (int m = 0; m < functions.size(); ++m) functions[m](); } Controller() {} virtual ~Controller() {} };
File example.i
%module example %{ #include "example.h" %} %include "example.h"
File example.py
import example def foo(): print("yey") def bar(): print("dog") def cat(): print("miaw") e = example.Controller() e.AddFunction(foo) e.AddFunction(bar) e.AddFunction(cat) # 预期依次打印yey、dog和miaw e.Execute()
我有两个问题:
- 该实现方向是否正确?即SWIG是否支持这种方式?
- 是否仅通过director特性即可达成我的目标?
解答
问题1:实现方向是否正确,SWIG是否支持?
方向可行,但SWIG默认不会自动处理std::function与Python函数的绑定。默认情况下,SWIG无法识别如何将Python函数对象转换为C++的std::function<void()>实例,因此现有代码直接编译会报错,需要额外添加类型映射(type mapping)来完成两者的转换适配。
问题2:仅用director特性能否达成目标?
不行。director特性核心是实现C基类的Python派生类,让C代码可以调用Python子类的虚函数,属于基于类继承的回调模式。而你需要的是直接传递独立的Python函数作为std::function参数,这和director的应用场景完全不同,必须通过编写SWIG类型映射来实现。
可行修改方案
修改example.i文件,添加针对std::function<void()>的类型映射,完成Python函数到C++函数对象的转换:
%module example %{ #include "example.h" #include <functional> %} // 类型映射:将Python可调用对象转换为std::function<void()> %typemap(in) const std::function<void()>& { if (!PyCallable_Check($input)) { PyErr_SetString(PyExc_TypeError, "Expected a callable object"); return NULL; } PyObject* func = Py_XINCREF($input); $1 = new std::function<void()>([func]() { PyObject* result = PyObject_CallObject(func, NULL); if (result == NULL) { PyErr_Print(); } else { Py_DECREF(result); } }); } // 清理std::function占用的内存 %typemap(freearg) const std::function<void()>& { delete $1; } %include "example.h"
修改后编译运行,Python中的函数即可被正确传递到C++层,Execute()调用时会依次打印预期内容。
内容的提问来源于stack exchange,提问作者José Joaquim
相关产品推荐
相关产品推荐

