Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using shared_ptr to abstract base as holder with boost.python

Our group is developing a numeric framework using C++. We whould now like to wrap basic parts of our framework to be available in Python. Our weapon of choice is Boost.Python since we're already Boost for other purposes as well. We solely use smart_ptrs to support polymorphism. The following snippet is a simple example of how we would apply the strategy pattern:

#include <boost/shared_ptr.hpp>
struct AbsStrategy
{
  virtual std::string talk( ) = 0;
};

typedef boost::shared_ptr<AbsStrategy> StrategyPtr;

struct Foo : AbsStrategy
{
  std::string talk( )
  {
    return "I am a Foo!";
  }
};

struct Bar : AbsStrategy
{
  std::string talk( )
  {
    return "I am a Bar!";
  }
};

struct Client
{
  Client( StrategyPtr strategy ) :
          myStrategy( strategy )
  {
  }

  bool checkStrategy( StrategyPtr strategy )
  {
    return ( strategy == myStrategy );
  }

  StrategyPtr myStrategy;
};

If I wrap the whole thing using Boost.Python like so

#include <boost/python.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE( BoostPython )
{
  class_<Foo>( "Foo" )
      .def( "talk", &Foo::talk );

  class_<Bar>( "Bar" )
      .def( "talk", &Bar::talk );

  class_<Client>( "Client", init<StrategyPtr>( ) )
      .def( "checkStrategy", &Client::checkStrategy );
}

the following warning pops up during compilation

C:/boost/include/boost-1_51/boost/python/object/instance.hpp:14:36: warning: type attributes ignored after type is already defined [-Wattributes]

When I try to use wrappers in python, I get the following errors

>>> from BoostPython import *
>>> foo = Foo()
>>> bar = Bar()
>>> client = Client(foo)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    Tree.__init__(Tree, Foo)
did not match C++ signature:
    __init__(_object*, boost::shared_ptr<AbsStrategy>)
>>> client = Client(bar)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    Tree.__init__(Tree, Bar)
did not match C++ signature:
    __init__(_object*, boost::shared_ptr<AbsStrategy>)

What is missing to make the whole thing work without changing our framework? The wrappers can be adapted freely of course.

like image 801
ToniBig Avatar asked Oct 05 '22 06:10

ToniBig


1 Answers

Ok I found the solution. One has to use implicitly_convertible in the module declaration as shown below.

#include <boost/python.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE( BoostPython )
{
  class_<Foo>( "Foo" )
      .def( "talk", &Foo::talk );

  class_<Bar>( "Bar" )
      .def( "talk", &Bar::talk );

  class_<Client>( "Client", init<StrategyPtr>( ) )
      .def( "checkStrategy", &Client::checkStrategy );

  implicitly_convertible<boost::shared_ptr<Foo> , StrategyPtr>();
  implicitly_convertible<boost::shared_ptr<Bar> , StrategyPtr>();
}
like image 151
ToniBig Avatar answered Oct 10 '22 03:10

ToniBig