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 traits class template `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
        {
            static unspecified value = false;
        };
    }}

A "traits class" which is inspected by Boost.Python to determine how wrapped classes can be constructed.

`value` is an integral constant convertible to bool of unspecified type.
Specializations may substitute a value convertible to `true` for `value` iff for each invocation of `class_<WrappedClass>::def(init<`type-sequence...`>())`, 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.

## 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;

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

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

        PyObject* m_self;
        int x;
    };

    // specialize has_back_reference for X
    namespace boost { namespace python
    {
      template <>
      struct has_back_reference<X>
      {
         enum { value = 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 x;
    };

    boost::shared_ptr<Y> Y_self(boost::shared_ptr<Y> self) const { 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 13 November, 2002

© Copyright Dave Abrahams 2002. All Rights Reserved.