5

I would like to expose objects wrapped in custom smart pointers in python using Boost::Python

The caveats

  • existing usage of the custom smart pointer is too pervasive to economically upgrade to the boost smart pointers
  • i would like to use the automatic dereferencing technique as described in several locations

The problem is that I cannot seem to get it quite right. Here's a sample code:

LegacyCode::Ptr -> legacy smart pointer code

LegacyCode::Session -> legacy object that's wrapped in the legacy smart pointer

namespace boost { namespace python
{
    template <class T> T* get_pointer(LegacyCode::Ptr<T> const& p)
    {
        return p.get();
    }


    template <typename T>
    struct pointee<LegacyCode::Ptr<T> >
    {
        typedef T type;
    };

}}*

BOOST_PYTHON_MODULE(pyro)
{
    using namespace boost::python;

    class_<LegacyCode::Session,LegacyCode::Ptr<LegacyCode::Session>>("Session")
                                          .def("get_type",&LegacyCode::Session::getType);
}

1 Answer 1

3

Here is a fully working example. You almost had it - you have to remove the get_pointer() from the boost::python namespace.

#include <boost/python.hpp>

// dummy smart ptr class
template <typename T> class Ptr {
  public:
    typedef T element_type;

    Ptr(): px(0) {}
    Ptr(T* p): px(p) {}

    // base operators
    T* operator->() { return px; }
    const T* operator->() const { return px; }
    T& operator*() { return *px; }
    const T& operator*() const { return *px; }

    // getters
    T* get() { return px; }
    const T* get() const { return px; }

  private:
    T* px;
};

// a dummy class that will be held by your custom smart pointer
class  Session {
  public:
    Session(int value) : value_(value) {}
    virtual ~Session() {}

    // a few methods to play with the class
    int value() const { return value_; };
    void value(int value) { value_ = value; }

  private:
    int value_;
};

// this emulates methods actually using your smart pointers
void print_value_1(const Ptr<Session>& s) {
  std::cout << "[by const reference] The value of this session is " << s->value() << std::endl;
}

void print_value_2(Ptr<Session> s) {
  std::cout << "[by value] The value of this session is " << s->value() << std::endl;
}

// here comes the magic
template <typename T> T* get_pointer(Ptr<T> const& p) {
  //notice the const_cast<> at this point
  //for some unknown reason, bp likes to have it like that
  return const_cast<T*>(p.get());
}

// some boost.python plumbing is required as you already know
namespace boost { namespace python {

  template <typename T> struct pointee<Ptr<T> > {
    typedef T type;
  };

} }

// now the module
BOOST_PYTHON_MODULE(example) {
  using namespace boost::python;
  class_<Session, Ptr<Session>, boost::noncopyable>("Session", init<int>());
  def("print_value_1", &print_value_1);
  def("print_value_2", &print_value_2);
}

You can test this with the following python code:

import example
s = example.Session(27)
example.print_value_1(s)
example.print_value_2(s)

We demonstrate with the example that boost.python will correctly run the conversion as required.

Sign up to request clarification or add additional context in comments.

2 Comments

To answer the unknown reason, the const_cast is required as a result of Ptr's definition, not because of Boost.Python. Ptr is applying const to its element when the Ptr itself is const. It is equivalent to the difference between const-pointer and pointer-to-const. For example, shared_ptr makes this distinction in the type itself: const shared_ptr<T> and shared_ptr<const T>.
I currently have the following problem: The CGAL libary has a class that basically wraps a Pointer (called Handle). I want to expose it as if it was a regular whatever-the-handle points to. But unfortunately the Handle doesn't have a element_type variable and therefore I always get compile errors. Any hints?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.