Python callback with SWIG wrapped type
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);
}
This fails because data hasn't gone through swig, and isn't a PyObject.
I tried using:
swigData = SWIG_NewPointerObj((void*)data, NULL, 0);
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.
So my questions are:
Whats the best way to invoke swig type wrapping?
Am I even going in the right direction here? Directors looked promising for implementing a callback, but I couldn't find an example of directors with python.
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.
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.
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);
...though this can only work if your Python function doesn't save its argument anywhere, as the shared_ptr
itself is not copied.
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);
Regardless, you then you have a Python-friendly SWIG object that's amenable to Py_BuildValue()
.
Hope this helps.
shared_ptr<T>
for unknown T
isn't a type, so SWIG can't hope to wrap it. What you need to do is provide a SWIG wrapping for each instance of shared_ptr
that you intend to use. So if for example you want to be able to doCallback()
with both shared_ptr<Foo>
and shared_ptr<Bar>
, you will need:
- A wrapper for
Foo
- A wrapper for
Bar
- Wrappers for
shared_ptr<Foo>
andshared_ptr<Bar>
.
You make those like so:
namespace boost {
template<class T> class shared_ptr
{
public:
T * operator-> () const;
};
}
%template(FooSharedPtr) boost::shared_ptr<Foo>;
%template(BarSharedPtr) boost::shared_ptr<Bar>;
精彩评论