2013-08-29 4 views
5

Ich möchte den Operator() mit Boost :: Python binden, aber ich sehe nicht wirklich, wie dies zu tun ist. Betrachten Sie das Beispiel:Boost Python Overload Operator()

C++:

class Queuer 
{ 

public: 
void Queuer::operator()(const qfc::Queue & iq, const qfc::Message & im) const; 
void Queuer::operator()(const qfc::Agent & ia, const qfc::Message & im) const; 
// some other overloaded operator() methods 

}; 

So in einem Python-Skript, nachdem das Modul Import ich verwende (genannt QFC), würde Ich mag tun:

Python:

>>> queuer = qfc.Queuer() 
// instantiating a Message an Agent and a Queue object 
>>> queuer(queue,message) 
>>> queuer(agent,message) 
>>> ... 

Hätten Sie eine Idee, wie es geht? vielleicht mit boost :: python call <>?

Danke, Kevin

Antwort

7

Wenn die Queuer Klasse auszusetzen, definieren eine __call__ Methode für jede Funktion Queuer::operator() Mitglied. Boost.Python wird das entsprechende Dispatching basierend auf den Typen durchführen. Die einzige Komplexität wird mit der Pointer-zu-Member-Funktionssyntax eingeführt, da der Aufrufer &Queuer::operator() disambiguieren muss.

Zusätzlich, wenn versucht wird, um abgeleitete Klassen in Python zu einer C++ Funktion mit einem Parameter der Basisklasse übergibt, dann einige zusätzliche Informationen Boost.Python ausgesetzt werden muss:

  • Die Base C++ Klasse Bedürfnisse mit class_ ausgesetzt werden. Zum Beispiel class_<BaseType>("Base").
  • Die abgeleitete Klasse muss ihre Basisklassen explizit auflisten, wenn sie mit bases_ angezeigt wird. Zum Beispiel class_<DerivedType, bases<BaseType> >("Derived"). Mit diesen Informationen kann Boost.Python während des Versands richtiges Casting durchführen.

Hier ist ein komplettes Beispiel:

#include <iostream> 

#include <boost/python.hpp> 

// Mockup classes. 
struct AgentBase {}; 
struct MessageBase {}; 
struct QueueBase {}; 
struct SpamBase {}; 
struct Agent: AgentBase {}; 
struct Message: MessageBase {}; 
struct Queue: QueueBase {}; 
struct Spam: SpamBase {}; 

// Class with overloaded operator(). 
class Queuer 
{ 
public: 

    void operator()(const AgentBase&, const MessageBase&) const 
    { 
    std::cout << "Queuer::operator() with Agent." << std::endl; 
    } 

    void operator()(const QueueBase&, const MessageBase&) const 
    { 
    std::cout << "Queuer::operator() with Queue." << std::endl; 
    } 

    void operator()(const SpamBase&, const MessageBase&) const 
    { 
    std::cout << "Queuer::operator() with Spam." << std::endl; 
    } 
}; 

/// Depending on the overlaod signatures, helper types may make the 
/// code slightly more readable by reducing pointer-to-member-function syntax. 
template <typename A1> 
struct queuer_overload 
{ 
    typedef void (Queuer::*type)(const A1&, const MessageBase&) const; 
    static type get(type fn) { return fn; } 
}; 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    // Expose only the base class types. Do not allow the classes to be 
    // directly initialized in Python. 
    python::class_<AgentBase >("AgentBase", python::no_init); 
    python::class_<MessageBase>("MessageBase", python::no_init); 
    python::class_<QueueBase >("QueueBase", python::no_init); 
    python::class_<SpamBase >("SpamBase", python::no_init); 

    // Expose the user types. These classes inerit from their respective 
    // base classes. 
    python::class_<Agent, python::bases<AgentBase> >("Agent"); 
    python::class_<Message, python::bases<MessageBase> >("Message"); 
    python::class_<Queue, python::bases<QueueBase> >("Queue"); 
    python::class_<Spam, python::bases<SpamBase> >("Spam"); 

    // Disambiguate via a varaible. 
    queuer_overload<AgentBase>::type queuer_op_agent = &Queuer::operator(); 

    python::class_<Queuer>("Queuer") 
    // Disambiguate via a variable. 
    .def("__call__", queuer_op_agent) 
    // Disambiguate via a helper type. 
    .def("__call__", queuer_overload<QueueBase>::get(&Queuer::operator())) 
    // Disambiguate via explicit cast. 
    .def("__call__", 
     static_cast<void (Queuer::*)(const SpamBase&, 
             const MessageBase&) const>(
      &Queuer::operator())) 
    ; 
} 

Und seine Nutzung:

>>> import example 
>>> queuer = example.Queuer() 
>>> queuer(example.Agent(), example.Message()) 
Queuer::operator() with Agent. 
>>> queuer(example.Queue(), example.Message()) 
Queuer::operator() with Queue. 
>>> queuer(example.Spam(), example.Message()) 
Queuer::operator() with Spam. 
0

Vielen Dank für Ihre Hilfe.

Eigentlich habe ich bereits die statische Besetzung Lösung getestet. In Wirklichkeit muss ich eine qfc::lqs::Message oder qfc::lqs::Agent oder qfc::lqs::Spam beim Aufruf queuer() übergeben. qfc::lqs::Message zum Beispiel, wie für qfc::lqs::Agent erben von qfc::Message und qfc::Agent jeweils.

So kann ich "cast" qfc::lqs::Message, qfc::lqs::Agent und qfc::lqs::Spam-qfc::Message, qfc::Agent und qfc::Spam, wenn der Bediener() aufgerufen wird, so dass die Unterschrift des Bedieners entspricht()?

Dies zu vermeiden, die Fehler unten:

error: invalid static_cast from type '<unresolved overloaded function type>' to type 'void (qfc::lqs::Queuer::*)(const qfc::lqs::Queue&, const qfc::lqs::Message&)const' 
+1

Betrachten Sie die ursprüngliche Frage mit dieser Information Bearbeitung für zukünftige Benutzer, die in dieser Frage führen. Außerdem aktualisierte ich die Antwort basierend auf dem, was meiner Meinung nach mit mehr der Frage übereinstimmt.Wenn ich die Frage missverstanden habe, kann ich mich gerne darauf konzentrieren. –