2016-08-19 127 views
4

https://stackoverflow.com/a/22965961/353337的幫助下,我能夠創建一個簡單的例子,說明如何通過Python將一個函數指針傳遞給函數。具體來說,通過SWIG傳遞函數指針的數組

%module test 

%{ 
#include "test.hpp" 
%} 

%pythoncallback; 
double f(double); 
%nopythoncallback; 

%ignore f; 
%include "test.hpp" 

我可以叫

import test 
test.f(13) 
test.myfun(test.f) 

,並得到預期的結果。現在

,我想改變的myfun簽名允許一個陣列的函數指針的(都具有相同的簽名),例如,

double myfun(std::vector<double (*)(double)>) 

我怎麼有調整.i文件?

理想的情況下,Python的通話將通過列表

test.myfun([test.f, test.g]) 
+0

@πάνταῥεῖ的基本工作的例子是一樣的,但問題是不同的。請取消標記爲dup。 –

+0

請改善你的問題第一。 –

+0

什麼不清楚? –

回答

1

我做下面的測試案例來說明你想要做什麼。它有一個真正落實myfun(const std::vector<double(*)(double)>&)讓生活更有趣一點:

#include <vector> 

double g(double x) { 
    return -x; 
} 

double f(double x) { 
    return x*x; 
} 

typedef double(*pfn_t)(double); 

std::vector<double> myfun(const std::vector<pfn_t>& funs, const double d) { 
    std::vector<double> ret; 
    ret.reserve(funs.size()); 
    for(auto && fn : funs) 
    ret.emplace_back(fn(d)); 
    return ret; 
} 

我希望所有我們需要做的,使這項工作是使用:

%include <std_vector.i> 
%template(FunVec) std::vector<double(*)(double)>; 
%template(DoubleVec) std::vector<double>; 
%include "test.h" 

然而痛飲3.0(來自Debian穩定版)不能正確處理FunVec,並且生成的模塊不能編譯。所以我增加了一個類型映射作爲一種解決方法:

%module test 

%{ 
#include "test.h" 
%} 

%pythoncallback; 
double f(double); 
double g(double); 
%nopythoncallback; 

%ignore f; 
%ignore g; 

%typemap(in) const std::vector<pfn_t>& (std::vector<pfn_t> tmp) { 
    // Adapted from: https://docs.python.org/2/c-api/iter.html 
    PyObject *iterator = PyObject_GetIter($input); 
    PyObject *item; 

    if (iterator == NULL) { 
     assert(iterator); 
     SWIG_fail; // Do this properly 
    } 

    while ((item = PyIter_Next(iterator))) { 
     pfn_t f; 
     const int res = SWIG_ConvertFunctionPtr(item, (void**)(&f), $descriptor(double(*)(double))); 
     if (!SWIG_IsOK(res)) { 
      assert(false); 
      SWIG_exception_fail(SWIG_ArgError(res), "in method '" "foobar" "', argument " "1"" of type '" "pfn_t""'"); 
     } 
     Py_DECREF(item); 
     tmp.push_back(f); 
    } 

    Py_DECREF(iterator); 
    $1 = &tmp; 
} 

%include <std_vector.i> 
// Doesn't work: 
//%template(FunVec) std::vector<double(*)(double)>; 
%template(DoubleVec) std::vector<double>; 
%include "test.h" 

基本上所有這樣做是「在」類型表添加一個函數指針類型的載體。該類型圖只是對從Python獲得的輸入進行迭代,並從Python迭代中構建臨時std::vector

這是足夠的下面的Python按預期工作:

import test 

print test.g 
print test.f 
print test.g(666) 
print test.f(666) 

print test.myfun([test.g,test.f],123)