我有以下代码,它实现了一个带有Python回调函数的简单C++类(ObjWithPyCallback).我们的想法是用"this"作为单个参数调用Python函数.
问题是,由于ObjWithPyCallback是一个SWIG包装对象,我需要SWIG typeinfo才能创建一个Python对象.
这个问题是它在SWIG生成的文件"ObjWithPyCallback_wrap.cxx"中.SWIG可以生成头文件吗?到目前为止,我还未能实现这一目标.
但是,即使使用头文件,SWIG和我的主要实现之间也存在循环依赖关系,这很烦人.如果可能的话,我想找到一种方法来避免它.最终ObjWithPyCallback最终存在于与Python绑定不同的共享库中.
是否有一个干净的方法来解决这个问题?我知道这篇文章,但它只涉及SWIG_NewPointerObj的机制.
在此先感谢您的帮助!
这是代码:
文件:example.py
import cb
def foo(x=None):
print("Hello from Foo!")
# I'd like x to be a reference to a ObjWithPyCallback object.
print(x)
o = cb.ObjWithPyCallback()
o.setCallback(foo)
o.call()
Run Code Online (Sandbox Code Playgroud)
文件:ObjWithPyCallback.h
#include <Python.h>
class ObjWithPyCallback
{
public:
ObjWithPyCallback();
void setCallback(PyObject *callback);
void call();
PyObject *callback_;
};
Run Code Online (Sandbox Code Playgroud)
文件:ObjWithCallback.cpp
#include "ObjWithPyCallback.h"
#include <iostream>
ObjWithPyCallback::ObjWithPyCallback() : callback_(NULL) {}
void ObjWithPyCallback::setCallback(PyObject* callback)
{
if (!PyCallable_Check(callback))
{
std::cerr << "Object is not callable.\n";
}
else
{
if ( callback_ …Run Code Online (Sandbox Code Playgroud) 这是我想要做的简化示例.假设我在test.h中有以下c ++代码
double f(double x);
double myfun(double (*f)(double x));
Run Code Online (Sandbox Code Playgroud)
现在这些功能的作用并不重要.重要的是myfun接受一个函数指针.
在我的接口文件中包含test.h文件后,我使用SWIG编译了一个python模块"test".现在,在Python中,我运行以下命令:
import test
f = test.f
Run Code Online (Sandbox Code Playgroud)
这创建了一个正常工作的函数f,它需要一个双精度函数.但是,当我尝试在python中将"f"传递给myfun时,会发生以下情况:
myfun(f)
TypeError: in method 'myfun', argument 1 of type 'double (*)(double)'
Run Code Online (Sandbox Code Playgroud)
我该如何解决?我想我的SWIG接口文件中需要一个typemap声明,但我不确定正确的语法是什么或放在哪里.我试过了
%typemap double f(double);
Run Code Online (Sandbox Code Playgroud)
但那没用.有任何想法吗?
我有一个wx.py.Shell.shell小部件,它允许用户执行与我的程序交互的python代码.我希望能够将用户在此空间中定义的函数传递给我的C++代码(通过wxswig生成的自定义小部件包装器)并执行它.
在我的C++代码中,我使用std :: function <>类来调用绑定函数(C++或Python)
所以我创建了一个简单的类来用函数调用操作符包装PyObject.但是当我尝试调用PyObject*时,我得到了一个段错误.
class PyMenuCallback
{
PyObject *Func;
public:
PyMenuCallback(const PyMenuCallback &op2);
PyMenuCallback(PyObject *func);
~PyMenuCallback ();
void operator() (int id);
};
/////////////////////////////////////////////////////////
PyMenuCallback::PyMenuCallback(PyObject *func)
: Func(func)
{
Py_XINCREF (Func);
if(!PyCallable_Check(Func))
cout << "Not a Callable Callback." << endl; //Throw an exception or something
}
PyMenuCallback::PyMenuCallback(const PyMenuCallback &op2)
: Func (op2.Func)
{
Py_XINCREF (Func);
if(!PyCallable_Check(Func))
cout << "Not a Callable Callback." << endl;
}
PyMenuCallback::~PyMenuCallback()
{
Py_XDECREF (Func);
}
void PyMenuCallback::operator() (int id)
{
cout << "Calling Callback" …Run Code Online (Sandbox Code Playgroud) 我看过很多类似的问题,但还没有找到解决我特定问题的方法.我试图SWIGify一些使用std :: function的C++ 11代码,所以我可以在我的Java应用程序中使用它.
我遇到过像这样的共享指针:
virtual std::shared_ptr<some::ns::TheThing> getTheThing(unsigned short thingID);
Run Code Online (Sandbox Code Playgroud)
并使用shared_ptr指令成功处理它们,如下所示:
%shared_ptr(some::ns::TheThing);
Run Code Online (Sandbox Code Playgroud)
我遇到过这样的共享指针向量:
virtual std::vector<std::shared_ptr<some::ns::TheThing>> getAllTheThings() const = 0;
Run Code Online (Sandbox Code Playgroud)
并使用如下模板成功处理它们:
%template(ThingVector) std::vector<std::shared_ptr<some::ns::TheThing>>;
Run Code Online (Sandbox Code Playgroud)
现在我有一个像这样的方法:
void registerThingCallback(std::function<void(std::shared_ptr<some::ns::TheThing>) > func);
Run Code Online (Sandbox Code Playgroud)
我无法让SWIG正确包装它.我已经尝试使用%回调,导演,%模板和%内联功能代码,因为我已经看到所有这些事情的例子,但是还没有能够得到任何似乎接近工作的东西.如果有帮助(清理和减少),这里有一个关于函数调用的更多上下文:
#include <functional>
namespace some {
namespace ns {
/**
* Hold some callbacks.
*/
class ThingCallbacks {
public:
/**
* Registers a callback
* @param func The callback function
*/
void registerThingCallback(std::function<void(std::shared_ptr<some::ns::TheThing>) > func);
};
}
}
Run Code Online (Sandbox Code Playgroud)
根据Flexo下面的答案,我更接近解决方案.我能够让下面的例子完全像宣传的那样工作.我尝试将它合并到我的实际代码中,但遇到了问题.为了扩展我之前的简化示例,这里是我对TheThing的定义:
#ifndef THE_THING_H
#define THE_THING_H
#include <string>
namespace some {
namespace ns …Run Code Online (Sandbox Code Playgroud) 显然,SWIG不理解std::function和破坏Python绑定.例如,这适用于C++:
// Somewhere in the API
typedef std::function<void(const UnitError & error)> UnitErrorHandler;
// Somewhere else in the API
void Unit::setErrorHandler(const UnitErrorHandler & handler) {}
// In the application code
unit->setErrorHandler([](const UnitError & error){
std::cerr << error << std::endl;
std::exit(1);
});
Run Code Online (Sandbox Code Playgroud)
但这会破坏代码(除了为了简单起见而有不同的行为,但这不是重点):
unit.setErrorHandler(lambda error: len(error))
Run Code Online (Sandbox Code Playgroud)
情况与def(普通)未绑定功能相同.那么,有没有人知道这方面的解决方法?