2009-10-16 71 views
2

我想所示为Python回调添加到C++库:Python的回调与SWIG包裹型

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); 
} 

失败的原因是数据没有经过痛饮走了,是不是的PyObject。

我试着使用:

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

但由于其模板,我真的不知道有什么用第二个参数。即使我对“正确的”SWIGTYPE进行了硬编码,它通常会在PyEval_CallObject上进行段错误。

所以我的问题是:

  1. 请告诉我援引痛饮 型包装的最佳方式?

  2. 我是否在正确的 方向?董事看起来 承诺实施 回调,但我找不到一个 董事与Python的例子。

更新:是如何产生正确的包装。我有其他函数返回shared_ptrs,并可以正确调用这些函数。

+0

感谢您的更新,但我想我很困惑。为什么不把你的shared_ptr 数据传递给你的Python函数?为什么要有一个doCallback()呢? –

+0

我的库封装了现有的C++库。 doCallback()只是底层库不时调用的处理函数。要清楚:我从来没有从python调用doCallback()。 – rogueg

+0

啊,当然!我添加了一个新的答案,可以更好地为您服务。 –

回答

0

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

您的中心问题是doCallback定义中的自由类型参数T。正如你在你的问题中所指出的那样,没有办法将SWIG对象从shared_ptr<T>中删除,但没有T的具体值: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友好呷对象是服从Py_BuildValue()

希望这会有所帮助。

+0

有道理。我希望在我的模板代码中插入SWIGType_really_long_name的方法有一些神奇的方法,但我猜不是。 – rogueg

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>; 
+0

感谢大卫的回应!不幸的是,我已经有了你描述的代码,所以生成了一个包装。 – rogueg