2011-03-17 14 views
17

Estoy tratando de exponer mis clases de C++ a Python usando Boost.Python. Aquí hay una versión simplificada de lo que estoy tratando de hacer:Boost.Python llamada por referencia: TypeError: No to_python (by-value) converter found for C++ type:

Tengo una clase A derivada de boost :: noncopyable y una segunda clase B con un método que toma como referencia una A como argumento.

class A : boost::noncopyable { /*...*/ }; 

class B { 

public: 

    virtual void do_something(A& a) { 
     /*...*/ 
    } 
}; 

estoy exponiendo las clases de la siguiente manera:

/* Wrapper for B, so B can be extended in python */ 
struct BWrap : public B, wrapper<B> { 

    void do_something(A &a) { 

     if (override do_something = this->get_override("do_something")) { 
      do_something(a); 
      return; 
     } 
     else { 
      B::do_something(a); 
     } 
    } 

    void default_do_something(A& a) { this->B::do_something(a); } 
}; 

BOOST_PYTHON_MODULE(SomeModule) { 

    class_<A, boost::noncopyable>("A"); 

    class_<BWrap, boost::noncopyable>("B") 
     .def("do_something", &B::do_something, &BWrap::default_do_something) 
    ; 
} 

que se extienden B en Python como esto:

test.py:

import SomeModule 


class BDerived(SomeModule.B): 

    def do_something(self, a): 
     pass 

y llame a la extendida B como este:

try { 
    py::object main = py::import("__main__"); \ 
    py::object global(main.attr("__dict__")); \ 
    py::object result = py::exec_file("test.py", global, global); \ 
    py::object pluginClass = global["BDerived"]; \ 
    py::object plugin_base = pluginClass(); \ 

    B& plugin = py::extract<B&>(plugin_base) BOOST_EXTRACT_WORKAROUND; 

    A a; 
    B.do_something(a); 
} 
catch (py::error_already_set) { 
    PyErr_Print(); 
} 

Sin embargo, esto da como resultado un mensaje de error:

TypeError: No to_python (by-value) converter found for C++ type: A 

Si A no se deriva de boost::noncopyable el código se ejecuta sin ningún error pero el argumento a en do_something(A& a) se copia durante la llamada a la función a pesar de que se aprobó en por referencia. Pero simplemente eliminar el requisito no copiable en A no es una opción, ya que está ahí por una razón.

¿Alguna sugerencia sobre cómo solucionar el problema?

Gracias.

+1

Para las personas que desembarquen aquí: hay un error reciente en Boost 1.60.0 que se parece mucho a esto, se debe solucionar en Boost 1.61.0, ver también https://github.com/boostorg/python/pull/59 –

+1

@KennethHoste ¡MUCHAS GRACIAS! me salvaste de varios días más si no semanas de error! tan feliz que encontré este pequeño comentario !! :) – Mangostaniko

Respuesta

15

Cambie B.do_something(a); a B.do_something(boost::ref(a));.

Consulte Calling Python Functions and Methods en el manual de impulso.

+0

¡Muchas gracias! Me diste la pista correcta. Aunque tuve que cambiarlo en la clase contenedora BWrap 'do_something (boost :: ref (a));' y no cuando llamo 'B.do_something (a);'. Increíble que incluso las horas de google nunca me dieron esa pista. ¡Gracias de nuevo! – Kai