Suppose I have the following two C++ classes (which I can't modify):
struct A
{
// stuff
};
struct B
{
// B will internally hold a reference to a
B(A& a, some_cpp_only_type arg);
};
I am trying to wrap the B class and hiding the some_cpp_only_type argument from the Python interface (there is no alternative constructor for B without this argument).
I have the following wrapper code right now:
using namespace boost::python;
boost::shared_ptr<B> make_B(A& a)
{
return boost::make_shared<B>(a, get_cpp_only_instance());
}
BOOST_PYTHON_MODULE(my_module)
{
class_<B, boost::noncopyable>("B", no_init)
.def("__init__", make_constructor(&make_B));
}
Right now this works because I'm holding a reference to the wrapped A object inside of Python. However, I would really like to keep this around at least until the instance of B is destroyed. I tried adding a with_custodian_and_ward_postcall call policy to make_constructor, but I get several pages of meaningless compiler errors (even from Clang). Here's the modified not working code:
using namespace boost::python;
boost::shared_ptr<B> make_B(A& a)
{
return boost::make_shared<B>(a, get_cpp_only_instance());
}
BOOST_PYTHON_MODULE(my_module)
{
class_<B, boost::noncopyable>("B", no_init)
.def("__init__", make_constructor(&make_B, with_custodian_and_ward_postcall<0,1>()));
}
How do I properly specify the call policy when using make_constructor?
Alternative attempt using make_function
I tried using the solution Tanner Sansbury posted here of wrapping with make_function instead, but this time even though the compile succeeds, I get a ValueError from inside of Python:
No to_python (by-value) converter found for C++ type: A
For reference, here is the code I tried which uses make_function (I get the same error with and without the custodian/ward call policy):
using namespace boost::python;
boost::shared_ptr<B> make_B(A& a)
{
return boost::make_shared<B>(a, get_cpp_only_instance());
}
void inter_make_B(object self, A& a)
{
auto constructor = make_constructor(&make_B);
constructor(self, a);
}
BOOST_PYTHON_MODULE(my_module)
{
class_<B, boost::noncopyable>("B", no_init)
.def("__init__", make_function(&inter_make_B, with_custodian_and_ward<1,2>()));
}
How do I properly write the wrapper for B which manages memory correctly without modifying the B class?