Boost.Python call by reference : TypeError: No to_python (by-value) converter found for C++ type:

13,117

Change B.do_something(a); to B.do_something(boost::ref(a));.

See Calling Python Functions and Methods in the boost manual.

Share:
13,117
Kai
Author by

Kai

Updated on June 14, 2022

Comments

  • Kai
    Kai almost 2 years

    I'm trying to expose my C++ Classes to Python using Boost.Python. Here is a simplyfied version of what i'm trying to do:

    I have a class A deriving from boost::noncopyable and a second class B with a method that takes a reference to A as an argument.

    class A : boost::noncopyable { /*...*/ };
    
    class B {
    
    public:
    
        virtual void do_something(A& a) {
            /*...*/
        }
    };
    

    I'm exposing the classes as follows:

    /* 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)
        ;
    }
    

    I extend B in python like this:

    test.py:

    import SomeModule
    
    
    class BDerived(SomeModule.B):
    
        def do_something(self, a):
            pass
    

    and call the extended B like this:

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

    However this results in an error message:

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

    If A isn't derived from boost::noncopyable the code runs without any errors but the argument a in do_something(A& a) gets copied during the function call even though it's passed in by reference. But just removing the noncopyable requirement on A isn't an option since it's there for a reason.

    Any suggestions how to solve the problem?

    Thanks.

  • Kai
    Kai about 13 years
    Thanks a lot! You gave me the right hint. Even though I had to change it in the wrapper class BWrap do_something(boost::ref(a)); and not when calling B.do_something(a);. Unbelievable that even hours of googling never gave me that hint. Thanks again!