问题描述
我正在尝试将 python 回调添加到 C++ 库,如图所示:
I'm trying to add a python callback to a C++ library as illustrated:
template<typename T> void doCallback(shared_ptr<T> data) {
PyObject* pyfunc; //I have this already
PyObject* args = Py_BuildValue("(O)", data);
PyEval_CallObject(pyfunc,args);
}
这会失败,因为数据没有经过 swig,也不是 PyObject.
This fails because data hasn't gone through swig, and isn't a PyObject.
我尝试使用:
swigData = SWIG_NewPointerObj((void*)data, NULL, 0);
但是因为它是一个模板,我真的不知道第二个参数该使用什么.即使我对正确"的 SWIGTYPE 进行硬编码,它通常也会在 PyEval_CallObject 上出现段错误.
But because its a template, I don't really know what to use for the second parameter. Even if I do hard code the 'correct' SWIGTYPE, it usually segfaults on PyEval_CallObject.
所以我的问题是:
调用 swig 的最佳方法是什么类型换行?
Whats the best way to invoke swigtype wrapping?
我是不是走在右边这里的方向?董事看了承诺实施一个回调,但我找不到董事使用 Python 的示例.
Am I even going in the rightdirection here? Directors lookedpromising for implementing acallback, but I couldn't find anexample of directors with python.
更新:正在生成正确的包装.我还有其他函数可以返回 shared_ptrs 并且可以正确调用它们.
Update: The proper wrapping is getting generated. I have other functions that return shared_ptrs and can call those correctly.
推荐答案
我的第一个回答完全误解了这个问题,所以让我们再试一次.
My first answer misunderstood the question completely, so let's try this again.
您的中心问题是 doCallback
定义中的自由类型参数 T
.正如您在问题中指出的那样,如果没有 T
的具体值,就无法从 shared_ptr
中创建 SWIG 对象:shared_ptr;
并不是真正的类型.
Your central problem is the free type parameter T
in the definition of doCallback
. As you point out in your question, there's no way to make a SWIG object out of a shared_ptr<T>
without a concrete value for T
: shared_ptr<T>
isn't really a type.
因此我认为您必须专门化:对于主机系统使用的 doCallback
的每个具体实例,为目标类型提供模板专门化.完成后,您可以生成一个 Python 友好的 data
包装,并将其传递给您的 Python 函数.最简单的技术可能是:
Thus I think that you have to specialize: for each concrete instantiation of doCallback
that the host system uses, provide a template specialization for the target type. With that done, you can generate a Python-friendly wrapping of data
, and pass it to your python function. The simplest technique for that is probably:
swigData = SWIG_NewPointerObj((void*)(data.get()), SWIGType_Whatever, 0);
...虽然这只有在您的 Python 函数没有将其参数保存在任何地方时才有效,因为 shared_ptr
本身没有被复制.
...though this can only work if your Python function doesn't save its argument anywhere, as the shared_ptr
itself is not copied.
如果确实需要保留对 data
的引用,则需要使用 SWIG 通常用于包装 shared_ptr
的任何机制.如果没有特殊情况的智能指针魔术,它可能是这样的:
If you do need to retain a reference to data
, you'll need to use whatever mechanism SWIG usually uses to wrap shared_ptr
. If there's no special-case smart-pointer magic going on, it's probably something like:
pythonData = new shared_ptr<Whatever>(data);
swigData = SWIG_NewPointerObj(pythonData, SWIGType_shared_ptr_to_Whatever, 1);
无论如何,您都有一个 Python 友好的 SWIG 对象,该对象适合 Py_BuildValue()
.
Regardless, you then you have a Python-friendly SWIG object that's amenable to Py_BuildValue()
.
希望这会有所帮助.
这篇关于带有 SWIG 包装类型的 Python 回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!