2016-08-19 1 views
4

Mit Hilfe von https://stackoverflow.com/a/22965961/353337 konnte ich ein einfaches Beispiel erstellen, wie man einen Funktionszeiger über Python in eine Funktion übergibt. Insbesondere mitÜbergabe von Funktionszeigern über SWIG

%module test 

%{ 
#include "test.hpp" 
%} 

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

%ignore f; 
%include "test.hpp" 

kann ich

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

nennen und die erwarteten Ergebnisse erzielen.

Nun würde Ich mag die Unterschrift von myfun ändern für eine Array von Funktionszeigern (alle mit der gleichen Signatur) zu ermöglichen, zB

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

Wie habe ich die Anpassung .i Datei?

Idealerweise würde der Python Anruf über eine Liste sein

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

@ πάντα ῥεῖ Das wichtigste Arbeitsbeispiel ist die gleiche, aber die Frage ist anders. Bitte entfernen Sie die Markierung als dup. –

+0

Bitte verbessern Sie Ihre Frage 1st. –

+0

Was ist unklar? –

Antwort

1

ich den folgenden Testfall gemacht zu veranschaulichen, was Sie zu tun versuchen. Es hat eine echte Umsetzung myfun(const std::vector<double(*)(double)>&), um das Leben ein wenig interessanter:

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

ich erwartet, dass alles, was wir tun müssen, würde um diese Arbeit zu machen, ist die Verwendung:

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

jedoch SWIG 3.0 (von Debian stable) behandelt dies FunVec nicht korrekt und das resultierende Modul kompiliert nicht. So habe ich eine typemap als Behelfslösung:

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

Grundsätzlich all dies tut, ist ein Add ‚in‘ typemap für den Vektor der Funktionszeigertypen. Diese Typumleitung iteriert einfach über die von Python gegebene Eingabe und erstellt ein temporäres std::vector aus einem iterierbaren Python.

Dies ist ausreichend, dass die folgende Python wie erwartet funktioniert:

import test 

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

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