2016-08-19 14 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) 

を呼び出し、期待どおりの結果を得ることができます。

今、私は私が適応しなければならないのはどのよう

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

、関数ポインタ(同じシグネチャを持つすべて)、例えばの配列可能にするためにmyfunの署名を変更したいです.iファイル?

理想的には、Pythonの呼び出しがリスト

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

πάντα@基本的な実施例ῥεῖは同じですが、質問は異なっています。 dupとしてマークを外してください。 –

+0

あなたの質問を一番良くしてください。 –

+0

不明な点は何ですか? –

答えて

1

経由だろう、私はあなたが何をしようとして説明するために、次のテストケースを作りました。

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

しかしSWIG 3.0(:

#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; 
} 

は、私たちはこの仕事をするために行う必要があるだろう、すべてが使用されることを期待:それは人生もう少し面白くするためにmyfun(const std::vector<double(*)(double)>&)の実際の実装を持っていますDebian stableから)は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" 

を基本的にこれが行うすべてが関数ポインタ型のベクトルのためのタイプマップ「で」1を追加することです。そのtypemapは、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) 
関連する問題