Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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);
}
share|improve this question

1 Answer

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.

share|improve this answer
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>. – Tanner Sansbury Feb 18 at 18:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.