Files
parameter_python/doc/python.rst
Daniel Wallin 184c036a59 more editing
[SVN r33964]
2018-10-14 18:08:55 +03:00

592 lines
18 KiB
ReStructuredText
Executable File

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The Boost Parameter Library Python Binding Documentation
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|(logo)|__
.. |(logo)| image:: ../../../../boost.png
:alt: Boost
__ ../../../../index.htm
:Authors: Daniel Wallin
:Contact: dalwan01@student.umu.se
:organization: `Boost Consulting`_
:date: $Date$
:copyright: Copyright David Abrahams, Daniel Wallin
2005. Distributed under the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt
or copy at http://www.boost.org/LICENSE_1_0.txt)
.. _`Boost Consulting`: http://www.boost-consulting.com
.. role:: class
:class: class
.. role:: concept
:class: concept
.. role:: function
:class: function
.. |KeywordsSpec| replace:: :concept:`KeywordsSpec`
.. contents::
:depth: 1
Introduction
------------
``boost/parameter/python.hpp`` introduces a group of def_visitors_ that can
be used to easily expose Boost.Parameter-enabled member functions to Python with
Boost.Python. It also provides a function template ``def()`` that can be used
to expose Boost.Parameter-enabled free functions.
.. _def_visitor: def_visitors_
.. _def_visitors: ../../../python/doc/v2/def_visitor.html
When binding a Boost.Parameter enabled function, the keyword tags
must be specified. Additionally, because Boost.Parameter enabled
functions are templates, the desired function signature must be
specified.
The keyword tags are specified as an `MPL Sequence`_, using the
pointer qualifications described in |KeywordsSpec|_ below. The
signature is also specifid as an `MPL sequence`_ of parameter
types. Additionally, ``boost::parameter::python::function`` and
``boost::parameter::python::def`` requires a class with forwarding
overloads. We will take a closer look at how this is done in the
tutorial section below.
.. The last two sentences are terribly vague. Which namespace is
.. ``function`` in? Isn't the return type always needed? What
.. else are we going to do other than pass these sequences to
.. function?
.. _`MPL Sequence`: ../../../mpl/doc/refmanual/sequences.html
.. _keywordsspec: `concept KeywordsSpec`_
Tutorial
--------
In this section we will outline the steps needed to bind a simple
Boost.Parameter-enabled member function to Python. Knowledge of the
Boost.Parameter macros_ are required to understand this section.
.. _macros: index.html
The class and member function we are interested in binding looks
like this::
#include <boost/parameter/keyword.hpp>
#include <boost/parameter/preprocessor.hpp>
#include <boost/parameter/python.hpp>
// First the keywords
BOOST_PARAMETER_KEYWORD(tag, title)
BOOST_PARAMETER_KEYWORD(tag, width)
BOOST_PARAMETER_KEYWORD(tag, height)
class window
{
public:
BOOST_PARAMETER_MEMBER_FUNCTION(
(void), open, tag,
(required (title, (std::string)))
(optional (width, (unsigned), 400)
(height, (unsigned), 400))
)
{
}
};
It defines a set of overloaded member functions called ``open`` with one
required parameter and two optional ones. To bind this member function to
Python we use the binding utility ``boost::parameter::python::function``.
``boost::parameter::python::function`` is a def_visitor_ that we'll instantiate
and pass to ``boost::python::class_::def()``.
To use ``boost::parameter::python::function`` we first need to define
a class with forwarding overloads.
::
struct open_fwd
{
template <class A0, class A1, class A2>
void operator()(
boost::type<void>, window& self, A0 const& a0, A1 const& a1, A2 const& a2
)
{
self.open(a0, a1, a2);
}
};
The first parameter, ``boost::type<void>``, tells the forwarding overload
what the return type should be. In this case we know that it's always void
but in some cases, when we are exporting several specializations of a
Boost.Parameter-enabled template, we need to use that parameter to
deduce the return type.
``window::open()`` takes a total of 3 parameters, so the forwarding function
needs to take three parameters as well.
.. Note::
We only need one overload in the forwarding class, despite the
fact that there are two optional parameters. There are special
circumstances when several overload are needed; see
`special keywords`_.
Next we'll define the module and export the class:
::
BOOST_PYTHON_MODULE(my_module)
{
using namespace boost::python;
namespace py = boost::parameter::python;
class_<window>("window")
.def(
"open", py::function<
open_fwd
, mpl::vector<tag::title, tag::width*, tag::height*>
, mpl::vector<void, std::string, unsigned, unsigned>
>()
);
}
.. @jam_prefix.append('import python ;')
.. @jam_prefix.append('stage . : my_module /boost/python//boost_python ;')
.. @my_module = build(
output = 'my_module'
, target_rule = 'python-extension'
, input = '/boost/python//boost_python'
, howmany = 'all'
)
.. @del jam_prefix[-1:]
``py::function`` is passed three parameters. The first one is the class
with forwarding overloads that we defined earlier. The second one is
an `MPL Sequence`_ with the keyword tag types for the function. The
pointer syntax means that the parameter is optional, so in this case
``width`` and ``height`` are optional parameters. The third parameter
is an `MPL Sequence`_ with the desired function signature. The return type comes first, and
then the parameter types:
.. parsed-literal::
mpl::vector<void, std::string, unsigned, unsigned>
*return type* *title* *width* *height*
.. @ignore()
That's it! This class can now be used in Python with the expected syntax::
>>> w = my_module.window()
>>> w.open(title = "foo", height = 20)
.. @example.prepend('import my_module')
.. @run_python(module_path = my_module)
.. Sorry to say this at such a late date, but this syntax really
.. strikes me as cumbersome. Couldn't we do something like:
class_<window>("window")
.def(
"open",
(void (*)(
tag::title(std::string),
tag::width*(unsigned),
tag::height*(unsigned))
)0
);
or at least:
class_<window>("window")
.def(
"open",
mpl::vector<
void,
tag::title(std::string),
tag::width*(unsigned),
tag::height*(unsigned)
>()
);
assuming, that is, that we will have to repeat the tags (yes,
users of broken compilers will have to give us function pointer
types instead).
------------------------------------------------------------------------------
concept |KeywordsSpec|
----------------------
A |KeywordsSpec| is an `MPL sequence`_ where each element is either:
* A *required* keyword of the form ``K``
* **or**, an *optional* keyword of the form ``K*``
* **or**, a *special* keyword of the form ``K**``
where ``K`` is a keyword tag type, as used in a specialization
of boost::parameter::keyword__.
__ ../../../parameter/doc/html/reference.html#keyword
The **arity range** of a |KeywordsSpec| is defined as the closed
range:
.. parsed-literal::
[ mpl::size<S> - number of *special* keyword tags in ``S`` , mpl::size<S> ]
For example, the **arity range** of ``mpl::vector2<x,y>`` is [2,2], the **arity range** of
``mpl::vector2<x,y*>`` is [2,2] and the **arity range** of ``mpl::vector2<x,y**>`` is [1,2].
.. Don't optional keywords affect the arity range?
*special* keywords
---------------------------------
Sometimes it is desirable to have a default value for a parameter that differ
in type from the parameter. This technique is useful for doing simple tag-dispatching
based on the presence of a parameter. An example_ of this is given in the Boost.Parameter
docs. The example uses a different technique, but could also have been written like this:
.. parsed-literal::
template <class ArgumentPack>
void dfs_dispatch(ArgumentPack& args, mpl::false\_)
{
*…compute and use default color map…*
}
template <class ArgumentPack, class ColorMap>
void dfs_dispatch(ArgumentPack& args, ColorMap colormap)
{
*…use colormap…*
}
template <class ArgumentPack>
void depth_first_search(ArgumentPack& args)
{
core::dfs_dispatch(args, args[color | mpl::false_()]);
}
.. _example: index.html#dispatching-based-on-the-presence-of-a-default
In the above example the type of the default for ``color`` is ``mpl::false_``, a
type that is distinct from any color map that the user might supply.
When binding the case outlined above, the default type for ``color`` will not
be convertible to the parameter type. Therefore we need to tag the ``color``
keyword as a *special* keyword. By doing this we tell the binding functions
that it needs to generate two overloads, one with the ``color`` parameter
present and one without. Had there been two *special* keywords, four
overloads would need to be generated. The number of generated overloads is
equal to ``2^N``, where ``N`` is the number of *special* keywords.
------------------------------------------------------------------------------
class template ``init``
-----------------------
Defines a named parameter enabled constructor.
.. parsed-literal::
template <class Keywords, class Signature>
struct init : python::def_visitor<init<Keywords, Signature> >
{
template <class Class>
void def(Class& class\_);
};
``init`` requirements
~~~~~~~~~~~~~~~~~~~~~
* ``Keywords`` is a model of |KeywordsSpec|.
* ``Signature`` is an MPL sequence of parameter types,
in the order dictated by ``Keywords``.
* For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity
range** of ``Keywords``, ``Class`` must support these
expressions:
======================= ============= =========================================
Expression Return type Requirements
======================= ============= =========================================
``Class(a0, ..., aN)`` \- ``a0``..\ ``aN`` are tagged arguments.
======================= ============= =========================================
.. Limit the width of these table cells. Some rst backend
.. processors actually produce different results depending on the
.. distribution of width.
Example
~~~~~~~
.. parsed-literal::
struct base { /\* ... \*/ };
class X : base
{
public:
BOOST_PARAMETER_CONSTRUCTOR(X, (base),
(required (x, \*))
(optional (y, \*))
)
};
BOOST_PYTHON_MODULE(..)
{
class_<X>("X")
.def(
init<
, mpl::vector2<tag::x, tag::y\*>
, mpl::vector2<int, int>
>()
);
}
------------------------------------------------------------------------------
class template ``call``
-----------------------
Defines a ``__call__`` operator, mapped to ``operator()`` in C++.
.. parsed-literal::
template <class Keywords, class Signature>
struct call : python::def_visitor<call<Keywords, Signature> >
{
template <class Class>
void def(Class& class\_);
};
``call`` requirements
~~~~~~~~~~~~~~~~~~~~~
* ``Keywords`` is a model of |KeywordsSpec|.
* ``Signature`` is an MPL sequence with the types of the keyword parameters,
in the order dictated by ``Keywords``, and the return type prepended.
* ``Class`` must support these expressions, where ``c`` is an instance of ``Class``:
=================== ==================== =======================================
Expression Return type Requirements
=================== ==================== =======================================
``c(a0, ..., aN)`` Convertible to ``R`` ``a0``..\ ``aN`` are tagged arguments.
=================== ==================== =======================================
For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``Keywords``.
Example
~~~~~~~
.. parsed-literal::
typedef parameter::parameters<
parameter::required<tag::x>
, parameter::optional<tag::y>
> call_parameters;
class X
{
public:
template <class Args>
int call_impl(Args const& args)
{
/\* ... \*/
}
template <class A0>
int operator()(A0 const& a0)
{
return call_impl(call_parameters()(a0));
}
template <class A0, class A1>
int operator()(A0 const& a0, A1 const& a1)
{
return call_impl(call_parameters()(a0,a1));
}
};
BOOST_PYTHON_MODULE(..)
{
class_<X>("X")
.def("f",
call<
, mpl::vector2<tag::x, tag::y\*>
, mpl::vector3<int, int, int>
>()
);
}
------------------------------------------------------------------------------
class template ``function``
---------------------------
Defines a named parameter enabled member function.
.. parsed-literal::
template <class Fwd, class Keywords, class Signature>
struct function : python::def_visitor<function<Fwd, Keywords, Signature> >
{
template <class Class, class Options>
void def(Class& class\_, char const* name, Options const& options);
};
``function`` requirements
~~~~~~~~~~~~~~~~~~~~~~~~~
* ``Keywords`` is a model of |KeywordsSpec|.
* ``Signature`` is an MPL sequence with the types of the keyword parameters,
in the order dictated by ``Keywords``, and the return type prepended.
* An instance of ``Fwd`` must support this expression:
============================================ ==================== ==============================================
Expression Return type Requirements
============================================ ==================== ==============================================
``fwd(boost::type<R>(), self, a0, …, aN)`` Convertible to ``R`` ``self`` is a reference to the object on which
the function should be invoked. ``a0````aN``
are tagged arguments.
============================================ ==================== ==============================================
For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``Keywords``.
Example
~~~~~~~
This example exports a member function ``f(int x, int y = …)`` to Python.
The |KeywordsSpec| ``mpl::vector2<tag::x, tag::y*>`` has an **arity range**
of [2,2], so we only need one forwarding overload.
.. parsed-literal::
class X
{
public:
BOOST_PARAMETER_MEMBER_FUNCTION((void), f, tag,
(required (x, \*))
(optional (y, \*))
)
{
/\* … \*/
}
};
struct f_fwd
{
template <class A0, class A1>
void operator()(boost::type<void>, X& self, A0 const& a0, A1 const& a1)
{
self.f(a0, a1);
}
};
BOOST_PYTHON_MODULE(..)
{
class_<X>("X")
.def("f",
function<
f_fwd
, mpl::vector2<tag::x, tag::y\*>
, mpl::vector3<void, int, int>
>()
);
}
.. This example is not consistent with your definition of arity
.. range, above. There are no special keywords in play here.
------------------------------------------------------------------------------
function template ``def``
-------------------------
Defines a named parameter enabled free function in the current Python scope.
.. parsed-literal::
template <class Fwd, class Keywords, class Signature>
void def(char const* name);
``def`` requirements
~~~~~~~~~~~~~~~~~~~~
* ``Keywords`` is a model of |KeywordsSpec|.
* ``Signature`` is an MPL sequence of parameters types,
in the order dictated by ``Keywords``, with the return type
prepended.
* An instance of ``Fwd`` must support this expression:
====================================== ==================== ======================================
Expression Return type Requirements
====================================== ==================== ======================================
``fwd(boost::type<R>(), a0, …, aN)`` Convertible to ``R`` ``a0````aN`` are tagged arguments.
====================================== ==================== ======================================
For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``Keywords``.
Example
~~~~~~~
This example exports a function ``f(int x, int y = …)`` to Python.
The |KeywordsSpec| ``mpl::vector2<tag::x, tag::y*>`` has an **arity range**
of [2,2], so we only need one forwarding overload.
.. parsed-literal::
BOOST_PARAMETER_FUNCTION((void), f, tag,
(required (x, \*))
(optional (y, \*))
)
{
/\* … \*/
}
struct f_fwd
{
template <class A0, class A1>
void operator()(boost::type<void>, A0 const& a0, A1 const& a1)
{
f(a0, a1);
}
};
BOOST_PYTHON_MODULE(…)
{
def<
f_fwd
, mpl::vector2<tag::x, tag::y\*>
, mpl::vector3<void, int, int>
>("f");
}
.. again, the undefined ``fwd`` identifier.
Portability
-----------
The Boost.Parameter Python binding library requires *partial template specialization*.
.. Oh. In that case, we don't have to worry so much about
.. compilers that can't parse function types.