Boost.Python - <boost/python/has_back_reference.hpp>

###  | # Boost.Python ## Header <boost/python/has_back_reference.hpp>

## Contents

Introduction
Classes
  Class template `has_back_reference`
    Class template `has_back_reference` synopsis
  Example(s)

## Introduction

`<boost/python/has_back_reference.hpp>` defines the predicate metafunction `has_back_reference<>`, which can be specialized by the user to indicate that a wrapped class instance holds a `PyObject*` corresponding to a Python object.

## Classes

### Class template `has_back_reference`

A unary metafunction whose `value` is true iff its argument is a `pointer_wrapper<>`.

#### Class template `has_back_reference` synopsis

    namespace boost { namespace python
    {
        template<class WrappedClass> class has_back_reference
        {
            typedef mpl::false_ type;
        };
    }}

A " metafunction" that is inspected by Boost.Python to determine how wrapped classes can be constructed.

`type::value` is an integral constant convertible to bool of unspecified type.
Specializations may substitute a `true`-valued integral constant wrapper for `type` iff for each invocation of `class_<WrappedClass>::def(init<` type-sequence...`>())` and the implicitly wrapped copy constructor (unless it is noncopyable), there exists a corresponding constructor `WrappedClass::WrappedClass(PyObject*,` type-sequence...`)`. If such a specialization exists, the `WrappedClass` constructors will be called with a "back reference" pointer to the corresponding Python object whenever they are invoked from Python. The easiest way to provide this nested `type` is to derive the specialization from `mpl::true_`.

## Example

### C++ module definition

    #include <boost/python/class.hpp>
    #include <boost/python/module.hpp>
    #include <boost/python/has_back_reference.hpp>
    #include <boost/python/handle.hpp>
    #include <boost/shared_ptr.hpp>

    using namespace boost::python;
    using boost::shared_ptr;

    struct X
    {
        X(PyObject* self) : m_self(self), m_x(0) {}
        X(PyObject* self, int x) : m_self(self), m_x(x) {}
        X(PyObject* self, X const& other) : m_self(self), m_x(other.m_x) {}

        handle<> self() { return handle<>(borrowed(m_self)); }
        int get() { return m_x; }
        void set(int x) { m_x = x; }

        PyObject* m_self;
        int m_x;
    };

    // specialize has_back_reference for X
    namespace boost { namespace python
    {
      template <>
      struct has_back_reference<X>
        : mpl::true_
      {};
    }}

    struct Y
    {
        Y() : m_x(0) {}
        Y(int x) : m_x(x) {}
        int get() { return m_x; }
        void set(int x) { m_x = x; }

        int m_x;
    };

    shared_ptr<Y>
    Y_self(shared_ptr<Y> self) { return self; }

    BOOST_PYTHON_MODULE(back_references)
    {
        class_<X>("X")
           .def(init<int>())
           .def("self", &X::self)
           .def("get", &X::get)
           .def("set", &X::set)
           ;

        class_<Y, shared_ptr<Y> >("Y")
           .def(init<int>())
           .def("get", &Y::get)
           .def("set", &Y::set)
           .def("self", Y_self)
           ;
    }

The following Python session illustrates that `x.self()` returns the same Python object on which it is invoked, while `y.self()` must create a new Python object which refers to the same Y instance.

### Python code

    >>> from back_references import *
    >>> x = X(1)
    >>> x2 = x.self()
    >>> x2 is x
    1
    >>> (x.get(), x2.get())
    (1, 1)
    >>> x.set(10)
    >>> (x.get(), x2.get())
    (10, 10)
    >>>
    >>>
    >>> y = Y(2)
    >>> y2 = y.self()
    >>> y2 is y
    0
    >>> (y.get(), y2.get())
    (2, 2)
    >>> y.set(20)
    >>> (y.get(), y2.get())
    (20, 20)

Revised 18 July, 2004

© Copyright Dave Abrahams 2002 .