1

I have a function that takes a std::shared_ptr, and I want to pass an object of Derived type to this function from python. Here's my class definitions:

struct AbstractBase {
    virtual void foo() = 0;
};

struct Derived : public AbstractBase {
    virtual void foo(){
        std::cout<<"Derived's foo!"<<std::endl;
    }
};

struct Unrelated {
    void bar(std::shared_ptr<AbstractBase> base_shared_ptr) {
        base_shared_ptr->foo();
    }
};
#endif /* CLASSES_H */

A simple pure C++ example does what I want:

int main()
{
    std::shared_ptr<Derived> d(new Derived);
    Unrelated u;
    u.bar(d);
}

output: Derived's foo!

Here is my Boost.Python Wrapper code:

#include <boost/python.hpp>
#include "classes.h"


BOOST_PYTHON_MODULE(shared_ptr_test) {
    using namespace boost::python;
    class_<AbstractBase,std::shared_ptr<AbstractBase>,boost::noncopyable>("AbstractBase",no_init);

    class_<Derived,std::shared_ptr<Derived>,bases<AbstractBase>,boost::noncopyable>("Derived");

    class_<Unrelated,std::shared_ptr<Unrelated>,boost::noncopyable>("Unrelated")
        .def("bar",&Unrelated::bar);
}

And here's my simple python test:

import shared_ptr_test

d=shared_ptr_test.Derived()
u=shared_ptr_test.Unrelated()
u.bar(d)

To my dismay, this does not work. It compiles fine, but when I run the python script, I get this error:

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    u.bar(d)
Boost.Python.ArgumentError: Python argument types in
    Unrelated.bar(Unrelated, Derived)
did not match C++ signature:
    bar(Unrelated {lvalue}, std::shared_ptr<AbstractBase>)

Changing bar to take a shared_ptr<Derived> fixes this, so I know that internally Boost.Python is managing the objects with shared_ptrs. Is there something more I need to do to get Boost.Python to realize that it is okay to pass a shared_ptr<Derived> to a function expecting a shared_ptr<Base>?

1 Answer 1

2

Boost.Python needs to be aware that a smart pointer to Derived can be converted to a smart pointer to AbstractBase. This can be accomplished by either of the following:

  • Using boost::shared_ptr. Boost.Python has code to handle implicit conversions between boost::shared_ptrs when their element_type are hierarchical.
  • Register an implicit conversion from std::shared_ptr<Derived> to std::shared_ptr<AbstractBase> via boost::python::implicitly_convertible. std::shared_ptr meets the concept requirements for the implicitly_convertible, so it only requires registering the conversion in the module definition:

    implicitly_convertible<std::shared_ptr<Derived>,          // Source
                           std::shared_ptr<AbstractBase> >(); // Target
    
Sign up to request clarification or add additional context in comments.

1 Comment

well,that's a little frustrating! I assumed that anything that worked for a boost::shared_ptr would work for a std::shared_ptr but I suppose this is just one of those edge cases we're gonna all have to deal with until everything is all nice and settled into C++11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.