# Boost.Python - <boost/python/lvalue_from_python.hpp>

###

# Boost.Python

## Header <boost/python/lvalue_from_python.hpp>

## Contents

Introduction
Classes
  Class Template `lvalue_from_python`
    Class Template `lvalue_from_python` synopsis
    Class Template `lvalue_from_python` constructor
  Class Template `get_member`
    Class Template `get_member` synopsis
    Class Template `get_member` static functions
Example

## Introduction

`<boost/python/lvalue_from_python.hpp>` supplies a facility for extracting C++ objects from within instances of a given Python type. This is typically useful for dealing with "traditional" Python extension types.

## Classes

### Class template `lvalue_from_python`

Class template `lvalue_from_python` will register from_python converters which extract a references and pointers to a C++ type which is held within an object of a given Python type. Its template arguments are:

`lvalue_from_python` Requirements
In the table below, `x` denotes an object of type `PythonObject&`
Parameter | Requirements | Description | Default
--- | --- | --- | ---
`python_type` | A compile-time constant `PyTypeObject*` | The Python type of instances convertible by this converter. Python subtypes are also convertible.
`Value` | A non-reference type. | The C++ type to be extracted
`PythonObject` | initial `sizeof(PyObject)` bytes are layout-compatible with `PyObject`. | The C++ type used to hold Python instances of `python_type`. | `Value`
`Extract` | `Value& v = Extract::execute(x);` | A type whose static `execute` function extracts a `Value` reference from within an object of type `PythonObject`. | An unspecified type whose `execute` function consists of `return x;`

If only the first two template arguments are supplied, these converters extract the entire `PythonObject` as a whole.

If the lifetime of the `lvalue_from_python` object ends before the last attempt to convert to one its target types, the behavior is undefined. The easiest way to ensure correct behavior is to declare an `lvalue_from_python` instance as a static local in a module init function, as shown in the example below.

#### Class template `lvalue_from_python` synopsis

    namespace boost { namespace python
    {
       template <
          PyTypeObject const* python_type
          , class Value
          , class PythonObject = Value
          , class Extract = unspecified
          >
       class lvalue_from_python
       {
          lvalue_from_python();
       };
    }}

#### Class template `lvalue_from_python` constructor

    lvalue_from_python();

Effects: Registers from_python converters which extract `Value&`, `Value const&`, `Value*`, or `Value const*` from Python objects of type `python_type` using `Extract::execute()`.

### Class template `get_member`

`get_member` can be used with `lvalue_from_python` in the common case where the C++ type to be extracted is a member of the Python object.

#### Class template `get_member` synopsis

    namespace boost { namespace python
    {
      template <class Class, class Member, Member (Class::*mp)>
      struct get_member
      {
         static Member& execute(Class& c);
      };
    }}

#### Class template `get_member` static functions

    Member& execute(Class& c);

Returns: `c.*mp`

## Example

This example presumes that someone has implemented the standard noddy example module from the Python documentation, and we want to build a module which manipulates `Noddy`s. Since `noddy_NoddyObject` is so simple that it carries no interesting information, the example is a bit contrived: it assumes you want to keep track of one particular object for some reason.

### C++ module definition

    #include <boost/python/reference.hpp>
    #include <boost/python/module.hpp>

    // definition lifted from the Python docs
    typedef struct {
       PyObject_HEAD
    } noddy_NoddyObject;

    using namespace boost::python;
    static ref cache;

    bool is_cached(noddy_NoddyObject* x)
    {
       return x == cache.get();
    }

    void set_cache(noddy_NoddyObject* x)
    {
       cache.reset((PyObject*)x, ref::increment_count);
    }

    BOOST_PYTHON_MODULE_INIT(noddy_cache)
    {
       module noddy_cache("noddy_cache")
          .def("is_cached", is_cached)
          .def("set_cache", set_cache)
          ;
    }

### Python code

    >>> import noddy
    >>> n = noddy.new_noddy()
    >>> import noddy_cache
    >>> noddy_cache.is_cached(n)
    0
    >>> noddy_cache.set_cache(n)
    >>> noddy_cache.is_cached(n)
    1
    >>> noddy_cache.is_cached(noddy.new_noddy())
    0

Revised 05 November, 2001

© Copyright Dave Abrahams 2002. All Rights Reserved.