I think I have been able to answer my own question. As Stephan had pointed out, it came down to the return_value_policy.

 

By defining the conversions (as in my last post) and using return_value_policy<return_by_value> I was able to have the translation handled appropriately when returning const Vec3d& types. The conversions also handled the case with a const Vec3d& as a parameter (and all other Vec3d references).

 

Many thanks to Stephan for pointing me in the right direction.

 

Here is the test in its final state:

 

#include <boost/python.hpp>

namespace p = boost::python;

 

class Vec3d {

                public:

                  Vec3d() {v[0] = v[1] = v[2] = 0.0;}

                  virtual ~Vec3d() {}

                  double operator[](size_t idx) const {return v[idx];}

                  double& operator[](size_t idx) {return v[idx];}

                private:

                  double v[3];

};

 

class UseVec3d {

                public:

                                UseVec3d() {}

                                UseVec3d(const Vec3d& vec) : v(vec) {}

                                virtual ~UseVec3d() {};

                                const Vec3d& get_vec() const {return v;}

                                void set_vec(const Vec3d& vec) {v = vec;}

                private:

                  Vec3d                 v;

};

 

struct vec3d_to_py {

static PyObject* convert(const Vec3d& src) {

  return Py_BuildValue("(ddd)", src[0], src[1], src[2]);

}

 

static PyTypeObject const *get_pytype ()  {

  return &PyTuple_Type;

}

};

 

struct vec3d_from_py  {

  vec3d_from_py()   {

    boost::python::converter::registry::push_back(

        &convertible,

        &construct,

        boost::python::type_id<Vec3d>()

        );

  }

 

  static void* convertible(PyObject* obj)   {

                                return obj;

  }

 

  static void construct(PyObject* self, p::converter::rvalue_from_python_stage1_data* data)   {

                typedef p::converter::rvalue_from_python_storage<Vec3d> storage_t;

 

                storage_t* store = reinterpret_cast<storage_t *>(data);

                void* mem = store->storage.bytes;

                new (mem) Vec3d();

               

                Vec3d* pv = reinterpret_cast<Vec3d *>(mem);

                PyArg_ParseTuple(self, "ddd", &((*pv)[0]), &((*pv)[1]), &((*pv)[2]));

                data->convertible = mem;

  }

};

 

 

BOOST_PYTHON_MODULE(raf)

{

                vec3d_from_py();

                p::to_python_converter<Vec3d, vec3d_to_py, true>();

 

                p::class_<UseVec3d>("UseVec3d")

                                .def(p::init<Vec3d>())

                                .def("get_vec", &UseVec3d::get_vec, p::return_value_policy<p::return_by_value>())

                ;

}