We have a smart_ptr template of our own, sort of cloned from
intrusive_ptr. But I'm having trouble with Python code passing subclass
objects managed by this smart_ptr to C++ methods accepting
smart_ptr<base class>.
Consider:
class Base: { ... };
class SubClass: public Base { ... };
class Interface
{
public:
void method(smart_ptr<Base> arg) const;
};
Of course SubClass* is implicitly convertible to Base*. In C++ code,
smart_ptr<SubClass> is even implicitly convertible to smart_ptr<Base>.
That is, given the definitions above, this C++ code compiles and runs
correctly:
Interface worker;
smart_ptr<SubClass> objp = new SubClass();
worker.method(objp);
We can inform Boost.Python that Base objects -- and, by implication,
SubClass as well -- are to be managed using smart_ptr<>.
class_("Base", no_init)
...
;
class_("SubClass")
...
;
We have many methods that accept smart_ptr<Base> and do appropriately
polymorphic things to SubClass and its siblings. However, if a Python
caller attempts to pass a SubClass object to a method accepting
smart_ptr<Base>:
obj = Extension.SubClass()
worker = Extension.Interface()
worker.method(obj)
we get the following runtime error:
Boost.Python.ArgumentError: Python argument types in
Interface.method(Interface, SubClass)
did not match C++ signature:
method(class Interface {lvalue}, class smart_ptr<class Base>)
That's true for both Boost 1.31 and Boost 1.32. We have not yet tried
this with Boost 1.33. We're using MSVC 7.1 on Windows XP Pro.
Okay, I know this is our fault, something's wrong with our smart_ptr
template definition. I know that because if I recompile with this:
#define smart_ptr boost::shared_ptr
instead of our own smart_ptr definition, it works just fine!
As noted earlier, our smart_ptr is a variant of boost::intrusive_ptr.
But it appears that either there's a mysterious requirement on the
smart_ptr template that we're not fulfilling, or there's special
recognition of boost::shared_ptr and possibly boost::intrusive_ptr in
Boost.Python.
What must we add to allow Boost.Python to recognize the legal conversion
from smart_ptr<SubClass> to smart_ptr<Base> when it does its argument
matching?
[Your next question is: why not just use one of the Boost smart
pointers? Short answer: that's what we WANTED to do! We tried shared_ptr
and ran afoul of the second-conversion-from-same-dumb-pointer problem;
we tried intrusive_ptr and got completely entangled in new cross-DLL
dependencies because intrusive_ptr doesn't deal well with incomplete
pointee types. Our smart_ptr is an attempt to trade away both issues, at
the cost of a mandatory pointee base class. It almost works, too, except
for this baffling bug...]
Thanks for your help.