boost python explicit typecast needed

boost-python, c++

Solution

When it comes to `boost::shared_ptr`, Boost.Python generally provides the desired functionality. In this particular case, there is no need to explicitly provide custom `to_python` converters as long as the module declaration defines that `Base` is held by `boost::shared_ptr<Base>`, and Boost.Python is told that `A` inherits from `Base`.

BOOST_PYTHON_MODULE(example) {
  using namespace boost::python;
  class_<Base, boost::shared_ptr<Base>, 
         boost::noncopyable>("Base", no_init);
  class_<A, bases<Base>,
         boost::noncopyable>("A", no_init);
  def("factory",  &factory);
  def("consumer", &consumer);
}

Boost.Python does not currently support custom lvalue converters, as it requires changes to the core library. Therefore, the `consumer` function either needs accept the `boost:shared_ptr<A>` by value or by const-reference. Either of the following signatures should work:

void consumer(boost::shared_ptr<A> a)
void consumer(const boost::shared_ptr<A>& a)

Here is a complete example:

#include <boost/python.hpp>
#include <boost/make_shared.hpp>

class Base
{
public:
  virtual ~Base() {}
};

class A
  : public Base
{
public:
  A(int value) : value_(value) {}
  int value() { return value_; };
private:
  int value_;
};

boost::shared_ptr<Base> factory()
{
  return boost::make_shared<A>(42);
}

void consumer(const boost::shared_ptr<A>& a)
{
  std::cout << "The value of object is " << a->value() << std::endl;
}

BOOST_PYTHON_MODULE(example) {
  using namespace boost::python;
  class_<Base, boost::shared_ptr<Base>, 
         boost::noncopyable>("Base", no_init);
  class_<A, bases<Base>,
         boost::noncopyable>("A", no_init);
  def("factory",  &factory);
  def("consumer", &consumer);
}

And the usage:

>>> from example import *
>>> x = factory()
>>> type(x)
<class 'example.A'>
>>> consumer(x)
The value of object is 42
>>> 

Since the module declaration specified that `Base` was a base-class for `A`, Boost.Python was able to resolves the type returned from `factory()` to `example.A`.

Problem

I have hybrid system (c++, boost python). In my c++ code there is very simple hierarchy ``` class Base{...} class A : public Base{...} class B : public Base{...} ``` 2 more business (on c++) methods ``` smart_ptr<Base> factory() //this produce instances of A and B void consumer(smart_ptr<A>& a) //this consumes instance of A ``` In python code I create instance of A with the `factory` and try to call consumer method: ``` v = factory() #I'm pretty sure that it is A instance consumer(v) ``` Absolutely reasonable I've got exception: Python argument types in consumer(Base) did not match to C++ signature: consumer(class A{lvalue}) It happens because no way how to tell Boost that some conversion efforts should be there. Is there some way how to specify dynamic casting behavior? Thank you in advance.

Original source