【问题标题】:Using SWIG for functions with functions as input parameter将 SWIG 用于函数作为输入参数的函数
【发布时间】:2016-11-11 06:13:29
【问题描述】:

考虑以下最小示例:我有一个 C++ 函数“myfun”,它接受一个数字和另一个函数作为输入,并返回在 x 处计算的函数:

double myfun(double x, double (*f)(double y))
{ 返回 f(x); }

我将此代码存储在“test.cpp”中。相应头文件'test.hpp'中的代码很简单

double myfun(double x, double (*f)(double y));

现在,我尝试使用 SWIG 从 Python 访问“myfun”。 'swig.i' 文件如下所示:

%module 测试
%{
#include "test.hpp"
%}
双myfun(双x,双(* f)(双y));

每当我尝试在 Python 中调用此函数时,例如与

从测试导入 myfun
myfun(2, lambda y: y**2)

我收到错误:

在方法“myfun”中,类型为“double (*)(double)”的参数 2

所以我的问题很简单:如何修改“swig.i”文件以便我可以将任何(合适的 Python)函数传递给“myfun”? (这个问题与How to wrap a c++ function which takes in a function pointer in python using SWIG'这个帖子有点相关,但不同的是,这里我没有在C++中指定输入函数,而是我想把它作为一个免费的'参数')。

【问题讨论】:

  • 如果您只是想要一个 python 解决方案,请考虑使用cython。 SWIG 已经(或曾经)倾向于在版本之间引入不兼容的语法更改。以前的雇主对此有巨大的问题。

标签: python c++ swig


【解决方案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 回调,因为没有足够的信息(唯一的解决方案是分配预编译的蹦床或在运行时生成 C++ 代码)。

如果您可以控制双方,但解决方法是创建一个包含回调的 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下载。

【讨论】:

    【解决方案2】:

    根据documentation(强调我的):

    虽然 SWIG 通常不允许用目标语言编写回调函数,但这可以通过使用类型映射和其他高级 SWIG 功能来完成。

    如果您想深入了解该主题,建议使用This 章节。
    无论如何,它看起来不是该工具的预期关键功能。
    你能做的最好的可能是获得一个围绕 Python 设计的解决方案,并且不能与其他目标语言一起使用,但这通常不是 Swig 用户想要的。

    请注意,您仍然可以使用 C/C++ 编写回调并将它们导出为常量,然后从目标语言中使用它们。
    有关详细信息,请参阅上面的 me 文档。

    【讨论】:

    • 我可以使用 Python 特定的解决方案,我只需要完成这项工作,我不打算深入研究 SWIG 代码。谢谢!
    • @user56643 这是 SWIG 文档,而不是代码。 ;-)
    猜你喜欢
    • 2014-12-31
    • 2022-12-12
    • 1970-01-01
    • 2014-01-22
    • 1970-01-01
    • 1970-01-01
    • 2021-06-12
    • 2020-12-23
    • 2022-06-29
    相关资源
    最近更新 更多