[英]Using SWIG for functions with functions as input parameter
考慮以下最小的例子:我有一個C ++函數'myfun',它接受一個數字和另一個函數作為輸入,並返回在x處計算的函數:
雙myfun(雙x,雙(* f)(雙y))
{return f(x); }
我將此代碼存儲在'test.cpp'中。 相應頭文件'test.hpp'中的代碼很簡單
double myfun(double x,double(* f)(double y));
現在,我嘗試使用SWIG從Python訪問'myfun'。 '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'? (這個問題與這篇文章有點相關如何包裝一個c ++函數,它使用SWIG接收python中的函數指針 '但不同之處在於我在C ++中沒有指定輸入函數,而是我想保持它為一個免費的“參數”)。
在編寫綁定時回調需要額外的處理,這在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 ++代碼)。
如果你可以控制雙方,但是解決方法是創建一個包含回調的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的函數也可以有上下文)。
可以從這里下載完整的示例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.