使用SWIG包装类型的Python回调

时间:2009-10-16 00:13:40

标签: c++ python swig

我正在尝试将python回调添加到C ++库中,如图所示:

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。

我尝试使用:

swigData = SWIG_NewPointerObj((void*)data, NULL, 0);

但是因为它是一个模板,我真的不知道如何使用第二个参数。即使我对“正确的”SWIGTYPE进行硬编码,它通常也会在PyEval_CallObject上进行段错误。

所以我的问题是:

  1. 什么是调用swig的最好方法 打包?

  2. 我甚至走右边 方向在这?董事看了 有希望实施一个 回调,但我找不到 使用python的导演示例。

  3. 更新:正在生成正确的包装。我有其他函数返回shared_ptrs并可以正确调用它们。

2 个答案:

答案 0 :(得分:0)

对于未知shared_ptr<T>

T不是一种类型,因此SWIG无法包装它。您需要做的是为您打算使用的每个shared_ptr实例提供SWIG包装。因此,如果您希望能够doCallback()同时使用shared_ptr<Foo>shared_ptr<Bar>,则需要:

  • Foo
  • 的包装器
  • Bar
  • 的包装器
  • shared_ptr<Foo>shared_ptr<Bar>
  • 的包装

你可以这样做:

namespace boost {
    template<class T> class shared_ptr
      {
      public:
          T * operator-> () const;
      };
  }

%template(FooSharedPtr) boost::shared_ptr<Foo>;
%template(BarSharedPtr) boost::shared_ptr<Bar>;

答案 1 :(得分:0)

我的第一个回答完全误解了这个问题,让我们再试一次。

您的核心问题是T定义中的免费类型参数doCallback。正如您在问题中指出的那样,shared_ptr<T>没有具体值的T中无法生成SWIG对象:shared_ptr<T>实际上并不是一个类型。

因此,我认为您必须专门化:对于主机系统使用的doCallback的每个具体实例化,为目标类型提供模板专门化。完成后,您可以生成一个Python友好的data包装,并将其传递给您的python函数。最简单的技术可能是:

swigData = SWIG_NewPointerObj((void*)(data.get()), SWIGType_Whatever, 0);

...虽然这只有在你的Python函数没有在任何地方保存其参数时才有效,因为shared_ptr本身不会被复制。

如果确实需要保留对data的引用,则需要使用SWIG通常用于包装shared_ptr的任何机制。如果没有特殊情况的智能指针魔术,它可能就像:

pythonData = new shared_ptr<Whatever>(data);
swigData = SWIG_NewPointerObj(pythonData, SWIGType_shared_ptr_to_Whatever, 1);

无论如何,你有一个易于使用Python的SWIG对象,可以使用Py_BuildValue()

希望这有帮助。