2009-10-16 70 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