2013-08-29 12 views
5

Mi piacerebbe associare l'operatore() usando Boost :: Python ma non vedo davvero come farlo. Si consideri l'esempio: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 

}; 

Quindi, in uno script Python, dopo aver importato il modulo che sto usando (chiamato QFC), vorrei fare:

Python:

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

Avete qualche idea su come farlo? forse con boost :: python chiama <>?

Grazie, Kevin

risposta

7

Quando esporre la classe Queuer, definire un metodo __call__ per ogni funzione Queuer::operator() membro. Boost.Python gestirà l'invio appropriato in base ai tipi. L'unica complessità è introdotta con la sintassi della funzione pointer-to-member, in quanto il chiamante è necessario per disambiguare lo &Queuer::operator().

Inoltre, quando si tenta di passare classi derivate in Python a una funzione C++ con un parametro della classe Base, quindi deve essere esposto a Boost.Python alcune informazioni aggiuntive: esigenze classe

  • La base C++ essere esposto con class_. Ad esempio, class_<BaseType>("Base").
  • La classe derivata deve elencare esplicitamente le sue classi di base quando viene esposta con bases_. Ad esempio, class_<DerivedType, bases<BaseType> >("Derived"). Con queste informazioni, Boost.Python può eseguire il cast corretto durante la spedizione.

Ecco un esempio completo:

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

e il suo utilizzo:

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

Grazie per il vostro aiuto.

In realtà ho già provato la soluzione statica. In realtà, ho bisogno di passare uno qfc::lqs::Message o qfc::lqs::Agent o qfc::lqs::Spam quando si richiama queuer(). qfc::lqs::Message ad esempio, come per qfc::lqs::Agent ereditato da qfc::Message e qfc::Agent rispettivamente.

Così posso "cast" qfc::lqs::Message, qfc::lqs::Agent e qfc::lqs::Spam-qfc::Message, qfc::Agent e qfc::Spam quando si invoca l'operatore() in modo che la firma corrisponde ad operatore()?

Questo per evitare l'errore mostrato di seguito:

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

consideri la modifica della domanda originale con questa informazione per i futuri utenti i quali corrono in questa domanda. Inoltre, ho aggiornato la risposta in base a ciò che ritengo allineare con altre domande.Se ho frainteso la domanda, sentitevi liberi di approfondirla. –