考虑以下最小的例子:我有一个C ++函数' myfun'它接受一个数字和另一个函数作为输入,并返回在x:
评估的函数双myfun(双x,双(* f)(双y))
{ return f(x); }
我将此代码存储在' test.cpp'中。相应头文件中的代码' test.hpp'简直就是
double myfun(double x,double(* f)(double y));
现在,我尝试访问“myfun'来自Python使用SWIG。 ' swig.i'文件如下:
%模块测试
%{
#include" test.hpp"
%}
double myfun(double x,double(* f)(double y));
每当我尝试在Python中调用此函数时,例如与
从测试导入myfun
myfun(2,lambda y:y ** 2)
我收到错误:
方法' myfun',参数2类型' double(*)(double)'
所以我的问题很简单:如何修改' swig.i'文件,以便我可以将任何(合适的Python)功能传递给' myfun&#39 ;? (这个问题与这篇文章有点相关How to wrap a c++ function which takes in a function pointer in python using SWIG'但不同之处在于我在C ++中没有指定输入函数,而是我希望将它保留为免费参数&# 39)。
答案 0 :(得分:1)
回写在编写绑定时需要额外的处理,这在SWIG中尚未得到支持,显然没有真正的解决方法。
重点是SWIG是关于从Python(和其他语言)调用C,而不是从C调用Python。
我们正在使用SIP而不是更复杂的绑定生成器(但是C ++ / Python特定的)。 SIP支持回调,甚至从C ++类继承Python类。
该工具非常强大,是PyQt绑定的引擎。
但请注意,Python中的可调用函数不仅仅是C ++中的函数,因为它可以包含上下文(它可以是闭包)。在C ++代码中:
int callF(int (*f)(int, int), int a, int b) {
return f(a, b);
}
只能调用一个纯粹的无上下文函数,因此传递一般的Python回调是不可能的,因为没有足够的信息(唯一的解决方案是分配预编译的trampolines或在运行时生成C ++代码)。 / p>
如果你可以控制双方,但是解决方法是创建一个包含回调的C类并在Python中派生它。例如:
struct CBack {
virtual int operator()(int x, int y) const {
return x+y;
}
virtual ~CBack() {}
};
int callF(const CBack& f,
int xv, int yv)
{
return f(xv, yv);
}
然后从CBack派生一个Python类并传递:
class Add(CBack):
def __call__(self, x, y):
return x + y
class Mul(CBack):
def __call__(self, x, y):
return x * y
print callF(Add(), 3, 7) # will print 10
print callF(Mul(), 3, 7) # will print 21
在这种情况下,你也可以传递一个(包裹的)lambda
def cback(f):
class PyCBack(CBack):
def __call__(self, x, y):
return f(x, y)
return PyCBack()
print callF(cback(lambda x, y: x*y), 3, 7)
换句话说,一个阻抗问题是C ++的函数与Python的函数不同(Python的函数也可以有上下文)。
可以从here下载完整示例。
答案 1 :(得分:0)
根据documentation(强调我的):
如果您想深入了解该主题,虽然 SWIG通常不允许使用目标语言编写回调函数,但这可以通过使用文字图和其他高级SWIG功能来实现。
This是建议的章节 无论如何,它看起来不是该工具的预期关键功能 您可以做的最好的事情是获得一个围绕Python设计的解决方案,并且不能与其他目标语言一起使用,但通常不是Swig的用户想要的。
请注意,您仍然可以使用C / C ++编写回调函数并将它们作为常量导出,然后使用目标语言中的它们。 有关详细信息,请参阅上述文档。