2016-08-19 2 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

@ πάντα ῥεῖ Основной рабочий пример такой же, но вопрос по-другому. Пожалуйста, отметьте, как дублировать. –

+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" 

Однако SWIG 3,0 (от стабильного Debian) не обрабатывает этот FunVec правильно, и полученный модуль не компилируется. Поэтому я добавил TypeMap как обходной путь:

%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" 

В основном все это делает добавьте «в» TypeMap для вектора типов указателей функции. Эта карта-карта просто выполняет итерацию над вводом, данным Python, и создает временный std::vector с помощью итерации Python.

Это достаточно, чтобы следующий 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) 
Смежные вопросы