2017-09-21 1 views
0

Ich habe eine C++ Klasse mit einer Methode, die dem aufrufbare Merkmale folgt Templat ist:Wie umschließt eine Template-Funktion, die der aufrufbaren Eigenschaft mit swig für Python folgt?

// A general data object 
struct MyObject 
{ 
    // ... hold some data, parameters, ... 
}; 

class MyOptimizationAlgorithm 
{ 
// ... 
public: 

    // An optimization function that uses a user-supplied 
    // callable to evaluate a data object: 
    template <class Callable> void optimize(MyObject o, Callable evaluator) { 
      // ... optimize, optimize, ... 
      auto value = evaluator(o); 
      // ... are we good enough yet? 
    } 
}; 

Hier ist die MyOptimizationAlgorithm Klasse implementiert einen Optimierungsalgorithmus. Der Benutzer liefert ein Datenobjekt (ein Doppelvektor, hier kein Problem) und eine Zielfunktion. Diese Funktion ist der vom Benutzer konfigurierbare Teil, auf den sich der Optimierungsalgorithmus stützt. Zum Beispiel könnten gültige aufrufbare Evaluatoren die Ackley-Funktion, die Cross-in-Tray-Funktion usw. implementieren.

Das Muster ist eigentlich ziemlich standardisiert: In C++ erlaubt mir das Callable/Prädikat-Merkmal, eine Methode zu erstellen, die ich weitergeben kann ein Functor oder ein std::function. ZB

struct Ackley 
{ 
    double operator()(MyObject const& o) 
    { 
     return /* ackley() applied to the values in o */ 
    } 
}; 

MyOptimizationAlgorithm optimizer; 
MyObject initialData; 

// ... supply data, 
// ... tune some parameters of the optimizer, then: 

optimizer.optimize(initialData, Ackley()); 

// ... or: 

optimizer.optimize(initalData, [](MyObject const& o) { /* ... */ }); 

Ich möchte jetzt einen Wrapper für Python mit swig erstellen. Das Ziel ist natürlich, die Auswerter Funktors in Python zu erstellen und an die Routine C++ übergeben, etwa so:

def CrossInTray: 
    def __call__(self, obj): 
     # calculate the cross-in tray function. 

optimzer = MyOptimizationAlgorithm() 
initial_data = MyObject() 
# ... again, setup, then: 
optimizer.optimize(initial_data, CrossInTray()) 

Ich bin neu in swig. Ich habe gesammelt, dass ich die Vorlage (unter Verwendung %template) spezialisieren muss und dass ich einen Direktor (%director) erstellen muss. Ich habe versucht, einen Functor Wrapper zu erstellen, etwa so:

%inline %{ 
    struct MyEvaluator 
    { 
     virtual double operator()(MyObject const& o) { return 0.0; } 
     virtual ~MyEvaluator() {} 
    }; 
%} 

%feature("director") MyEvaluator; 
%extend MyAlgorithm { 
    %template(runPredicated) optimize<MyEvaluator>; 
} 

Ich hatte gehofft, dass ich dann Subklassen meines Functor in Python erstellen könnte, definieren __call__ dort und habe es verwendet, aber es ruft nur MyEvaluator::operator(), das ist ziemlich sinnlos (und verständlich, da ich die Vorlage auf MyEvaluator spezialisiert habe).

Also: Was muss ich der Schnittstellendatei hinzufügen, um die aufrufbare Eigenschaft von C++ - Code in Python zu verwenden?

+0

Die Eigenschaft kann niemals mit einer Python-Implementierung realisiert werden, '% template (runPredicated) optimiert ;' ist eine Template-Instanziierung und zum Zeitpunkt der Instanziierung muss 'MyEvaluator' bekannt sein. Was Sie einfach tun können, ist eine Schnittstelle in 'C++' definiert, implementieren Sie diese in Python und verwenden Sie diese in C++ und sogar in einem C++ - Programm, siehe https://stackoverflow.com/questions/9040669/how-can-i-implement -ac-class-in-python-zu-called-by-c/9042139 –

Antwort

0

Dies ist ein bisschen zu allgemein. Wenn Sie sich selbst beschränken möchten, können :: Funktion Schnittstelle std wie

class MyOptimizationAlgorithm 
{ 
// ... 
public: 

    // An optimization function that uses a user-supplied 
    // callable to evaluate a data object: 
    template<typename T> 
    void optimize(MyObject o, std::function<T(MyObject const&)> evaluator) { 
      // ... optimize, optimize, ... 
      T value = evaluator(o); 
      // ... are we good enough yet? 
    } 
}; 

eine mögliche Wrapper aussehen

class MyOptimizationAlgorithm: 
    def `optimize<double>` as optimize(o: MyObject, evaluator: (o: MyObject)->float) 

und kann mit jeder Python-Funktion unter MyObject und Zurückgeben eines Schwimmers aufgerufen werden. Der Python-Code in der Frage sollte einfach funktionieren.

Der obige Wrapper ist PyCLIF (anstelle von SWIG).

Verwandte Themen