本文介绍了带有 SWIG 包装类型的 Python 回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 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.

所以我的问题是:

  1. 调用 swig 的最佳方法是什么类型换行?

  1. 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 回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 06:00