[C++-sig] register_ptr_to_python and get_pointer

Marc Kwiatkowski Marc.Kwiatkowski at veritas.com
Thu Dec 18 02:26:57 CET 2003


I'm trying to integrate Boost::python templates to expose a bunch of legacy classes.  We have our own reference-counting pointer template, ref_ptr; the moral equivalent of shared_count.  Having gotten basic classes, I set out to figure out how to to expose ref_ptr.  Looking at the notes on this list and the PythonInfoWiki I figured out how to wrap my classes with shared_ptr using register_ptr_to_python.  I then attempted to switch from shared_ptr to our own ref_ptr and kept getting cryptic errors like the following:

    boost\python\object\make_ptr_instance.hpp(31) : error C2784: 'T *boost::python::get_pointer(const boost::python::handle<T> &)' : could not deduce template argument for 'const boost::python::handle<T> &' from 'const ref_ptr<TRef>'

I am not a C++ template god by any stretch of the imagination, but I was determined to try to make this work or at least understand why it wouldn't.  After dissecting pointee, pointer_holder, make_instance, et al., I finally realized that my problem was that there was no get_pointer template function for class instances of my ref_ptr template.  All I needed to do was the following:

  namespace boost { namespace python {

  /* Need to provide get_pointer template function for SigFoundation::ref_ptr, so that boost holder templates
      can use it to extract values. */
 
  template <class T> T* get_pointer(example::ref_ptr<T> const& p) {
    return p.get();
  }
  }} // namespace boost::python


With this in place, I was able to get my version of the register_ptr_to_python sample working.  (It's included below in toto for your reference.)

I guess the question I have ism why isn't this documented anywhere?  I have found boost::python to be the best library for getting at C++ stuff from python, but the terseness of the documentation and lack of examples for integrating with legacy code is frustrating.  Also, if this isn't the correct way to do this, I'd be glad to know what is.


Here is the register_python_to_pointer sample modified for a thirdparty ref-counting-pointer template:

Thanks.

=== test.cpp ===

#include <xstring>
#include <boost/python/class.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/call_method.hpp>
#include <boost/python/register_ptr_to_python.hpp>
#include <boost/python/exception_translator.hpp>
#include <boost/python/overloads.hpp>
#include <boost/python/pointee.hpp>
#include <boost/python/converter/arg_from_python.hpp>

namespace boost { namespace python {

/* Need to provide get_pointer template function for example::ref_ptr, so that boost holder templates
   can use it to extract values. */

template <class T> T* get_pointer(example::ref_ptr<T> const& p) {
    return p.get();
}

}} // namespace boost::python

namespace example { namespace test { namespace ref_ptr {

using boost::shared_ptr;
using boost::is_pointer;
using boost::remove_pointer;
using boost::python::call_method;
using boost::python::class_;
using boost::python::def;
using boost::python::init;
using boost::python::pointee;
using boost::python::register_exception_translator;
using boost::python::register_ptr_to_python;
using boost::python::to_python_converter;

using std::wstring;

class C {
public:
    C() : str(L"hello ref_ptr") {}
    C(wstring const& aString) : str(aString) {}
    virtual ~C() {}
        
    virtual wstring GetString() const {
        return str;
    }
        
private:
    wstring str;
};

class Factory {
public:
    Factory() {}
        
    CVxRefPtr< C > NewC(wstring const& aString) {
        return CVxRefPtr< C >(new C(aString));
    }

    wstring frpc(CVxRefPtr< C > c) {return c->GetString();}
    wstring fconstc(C const& c) { return c.GetString();}
    wstring fc(C& c) { return c.GetString();}
};
    
class C_Wrapper: public C {
public:
    C_Wrapper(PyObject* self_) : C(), self(self_) {}
    C_Wrapper(PyObject* self_, wstring const& aString) : C(aString), self(self_) {}
    C_Wrapper(PyObject* self_, const C& c): self(self_), C(c) {}

    ~C_Wrapper() {}
    wstring GetString() const { return call_method<wstring>(self, "GetString"); }    
    wstring default_GetString() const { return C::GetString(); }    
    PyObject* self;
};

BOOST_PYTHON_MODULE(test) {

    class_<C, C_Wrapper >("C")
        .def(init<wstring const&>())
        .def("GetString", &C::GetString, &C_Wrapper::default_GetString);

    register_ptr_to_python< CVxRefPtr< C > >();

    class_<Factory>("Factory")
        .def("NewC", &Factory::NewC)
	.def("frpc", &Factory::frpc)
	.def("fconstc", &Factory::fconstc)
	.def("fc", &Factory::fc);

}

}}} // namespace example::test::ref_ptr

=== test.py ===

from test import C, Factory

f=Factory()

x=f.NewC("fba")

c=C("foo")

f.frpc(x) # succeeds

f.frpc(c) # fails

f.fc(x) # succeeds

f.fc(c) # succeeds

f.fconstc(x) # succeeds

f.fconstc(c) # succeeds

-- 
marc.kwiatkowski at veritas.com






More information about the Cplusplus-sig mailing list