I've run into an edge case with Boost.Python that seems like it should work but doesn't.
What I have is a Base and a Derived class that I am storing in std::shared_ptr's on the python side. What I would like to do is pass a Derived type shared_ptr to a function that accepts a Base shared_ptr by reference.
I've done some research and have learned about implicitly_convertible and have attempted to employ it to fix the problem but without success (although it does help in some other situations). Passing a Derived to function that accepts a Base& works with this but if they're wrapped in shared_ptr then it fails.
What I get currently is the message below:
Boost.Python.ArgumentError: Python argument types in
test_bed_bindings.acceptBaseSharedPtrRef(Derived) did not match C++ signature:
acceptBaseSharedPtrRef(std::shared_ptr<(anonymous namespace)::Base> {lvalue})
See below for example code:
C++ Binding code
#define BOOST_PYTHON_STATIC_LIB
#define BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY 1
#include <boost/optional.hpp>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <memory>
namespace
{
class Base
{
};
class Derived : public Base
{
};
std::shared_ptr<Base> getBaseSharedPtr()
{
auto retVal = std::make_shared<Base>();
std::cout << "Creating Base shared_ptr - " << retVal.get() << std::endl;
return retVal;
}
std::shared_ptr<Derived> getDerivedSharedPtr()
{
auto retVal = std::make_shared<Derived>();
std::cout << "Creating Derived shared_ptr - " << retVal.get() << std::endl;
return retVal;
}
void acceptBaseSharedPtrRef(std::shared_ptr<Base>& base)
{
std::cout << "acceptBaseSharedPtrRef() with " << base.get() << std::endl;
}
void acceptBaseSharedPtrConstRef(const std::shared_ptr<Base>& base)
{
std::cout << "acceptBaseSharedPtrConstRef() with " << base.get() << std::endl;
}
void acceptBaseSharedPtrCopy(std::shared_ptr<Base> base)
{
std::cout << "acceptBaseSharedPtrCopy() with " << base.get() << std::endl;
}
//
void acceptBaseRef(Base base)
{
}
} // namespace
namespace bindings
{
BOOST_PYTHON_MODULE(test_bed_bindings)
{
PyEval_InitThreads();
Py_Initialize();
using namespace boost::python;
def("getBaseSharedPtr", &::getBaseSharedPtr);
def("getDerivedSharedPtr", &::getDerivedSharedPtr);
def("acceptBaseSharedPtrRef", &::acceptBaseSharedPtrRef);
def("acceptBaseSharedPtrConstRef", &::acceptBaseSharedPtrConstRef);
def("acceptBaseSharedPtrCopy", &::acceptBaseSharedPtrCopy);
def("acceptBaseRef", &::acceptBaseRef);
class_<Base, std::shared_ptr<Base> >("Base")
.def(init<>())
;
class_<Derived, bases<Base>, std::shared_ptr<Derived> >("Derived")
.def(init<>())
;
implicitly_convertible<Derived, Base>();
implicitly_convertible<std::shared_ptr<Derived>, std::shared_ptr<Base>>();
} // BOOST_PYTHON
} // namespace bindings
Python execution code
import test_bed_bindings
baseObj = test_bed_bindings.Base()
derivedObj = test_bed_bindings.Derived()
test_bed_bindings.acceptBaseRef( baseObj )
test_bed_bindings.acceptBaseRef( derivedObj )
baseSharedPtr = test_bed_bindings.getBaseSharedPtr()
derivedSharedPtr = test_bed_bindings.getDerivedSharedPtr()
test_bed_bindings.acceptBaseSharedPtrCopy( baseSharedPtr )
test_bed_bindings.acceptBaseSharedPtrCopy( derivedSharedPtr )
test_bed_bindings.acceptBaseSharedPtrConstRef( baseSharedPtr )
test_bed_bindings.acceptBaseSharedPtrConstRef( derivedSharedPtr )
test_bed_bindings.acceptBaseSharedPtrRef( baseSharedPtr )
test_bed_bindings.acceptBaseSharedPtrRef( derivedSharedPtr )
Sample Output
Creating Base shared_ptr - 0x276fdb8
Creating Derived shared_ptr - 0x276fde8
acceptBaseSharedPtrCopy() with 0x276fdb8
acceptBaseSharedPtrCopy() with 0x276fde8
acceptBaseSharedPtrConstRef() with 0x276fdb8
acceptBaseSharedPtrConstRef() with 0x276fde8
acceptBaseSharedPtrRef() with 0x276fdb8
Traceback (most recent call last):
File "test_script.py", line 21, in <module>
test_bed_bindings.acceptBaseSharedPtrRef( derivedSharedPtr )
Boost.Python.ArgumentError: Python argument types in
test_bed_bindings.acceptBaseSharedPtrRef(Derived)
did not match C++ signature:
acceptBaseSharedPtrRef(std::shared_ptr<(anonymous namespace)::Base> {lvalue})