123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778 |
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- The Boost Parameter Library Python Binding Documentation
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- :Authors: David Abrahams, Daniel Wallin
- :Contact: dave@boost-consulting.com, daniel@boostpro.com
- :organization: `BoostPro Computing`_
- :date: $Date$
- :copyright: Copyright David Abrahams, Daniel Wallin
- 2005-2009. 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)
- :abstract: Makes it possible to bind Boost.Parameter-enabled
- functions, operators and constructors to Python.
- |(logo)|__
- .. |(logo)| image:: ../../../../boost.png
- :alt: Boost
- __ ../../../../index.htm
- .. _`BoostPro Computing`: http://www.boostpro.com
- .. role:: class
- :class: class
- .. role:: concept
- :class: concept
- .. role:: function
- :class: function
- .. |ParameterSpec| replace:: :concept:`ParameterSpec`
- .. 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| replace:: ``def_visitor``
- .. |def_visitors| replace:: ``def_visitors``
- .. _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 |ParameterSpec|_ 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 keyword tags and associated argument types are specified as an `MPL
- Sequence`_, using the function type syntax described in |ParameterSpec|_
- below. 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
- .. _parameterspec: `concept ParameterSpec`_
- 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:
- .. parsed-literal::
- #include <boost/parameter/keyword.hpp>
- #include <boost/parameter/preprocessor.hpp>
- #include <boost/parameter/python.hpp>
- #include <boost/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))
- )
- {
- *… function implementation …*
- }
- };
- .. @example.prepend('#include <cassert>')
- .. @example.replace_emphasis('''
- assert(title == "foo");
- assert(height == 20);
- assert(width == 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. This is needed because ``window::open()``
- is a function template, so we can't refer to it in any other way.
- ::
- 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;
- namespace mpl = boost::mpl;
- class_<window>("window")
- .def(
- "open", py::function<
- open_fwd
- , mpl::vector<
- void
- , tag::title(std::string)
- , tag::width*(unsigned)
- , tag::height*(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[:]
- ``py::function`` is passed two 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 and argument types for the function
- specified as function types. The pointer syntax used in ``tag::width*`` and
- ``tag::height*`` means that the parameter is optional. The first element of
- the `MPL Sequence`_ is the return type of the function, in this case ``void``,
- which is passed as the first argument to ``operator()`` in the forwarding
- class.
- .. 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 |ParameterSpec|
- -----------------------
- A |ParameterSpec| is a function type ``K(T)`` that describes both the keyword tag,
- ``K``, and the argument type, ``T``, for a parameter.
- ``K`` is either:
- * A *required* keyword of the form ``Tag``
- * **or**, an *optional* keyword of the form ``Tag*``
- * **or**, a *special* keyword of the form ``Tag**``
- where ``Tag`` is a keyword tag type, as used in a specialization
- of |keyword|__.
- .. |keyword| replace:: ``boost::parameter::keyword``
- __ ../../../parameter/doc/html/reference.html#keyword
- The **arity range** for an `MPL Sequence`_ of |ParameterSpec|'s 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(int),y(int)>`` is ``[2,2]``,
- the **arity range** of ``mpl::vector2<x(int),y*(int)>`` is ``[2,2]`` and the
- **arity range** of ``mpl::vector2<x(int),y**(int)>`` is ``[1,2]``.
- *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. For example:
- .. 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::
- namespace core
- {
- template <class ArgumentPack>
- void dfs_dispatch(ArgumentPack const& args, mpl::false\_)
- {
- *…compute and use default color map…*
- }
- template <class ArgumentPack, class ColorMap>
- void dfs_dispatch(ArgumentPack const& args, ColorMap colormap)
- {
- *…use colormap…*
- }
- }
- template <class ArgumentPack>
- void depth_first_search(ArgumentPack const& args)
- {
- core::dfs_dispatch(args, args[color | mpl::false_()]);
- }
- .. @example.prepend('''
- #include <boost/parameter/keyword.hpp>
- #include <boost/parameter/parameters.hpp>
- #include <boost/mpl/bool.hpp>
- #include <cassert>
- BOOST_PARAMETER_KEYWORD(tag, color);
- typedef boost::parameter::parameters<tag::color> params;
- namespace mpl = boost::mpl;
- ''')
- .. @example.replace_emphasis('''
- assert(args[color | 1] == 1);
- ''')
- .. @example.replace_emphasis('''
- assert(args[color | 1] == 0);
- ''')
- .. @example.append('''
- int main()
- {
- depth_first_search(params()());
- depth_first_search(params()(color = 0));
- }''')
- .. @build()
- .. .. _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. This is done by specifying the tag as
- ``tag::color**`` when binding the function (see `concept ParameterSpec`_ for
- more details on the tagging). 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\
- :sup:`N`, where ``N`` is the number of *special* keywords.
- ------------------------------------------------------------------------------
- class template ``init``
- -----------------------
- Defines a named parameter enabled constructor.
- .. parsed-literal::
- template <class ParameterSpecs>
- struct init : python::def_visitor<init<ParameterSpecs> >
- {
- template <class Class>
- void def(Class& class\_);
- template <class CallPolicies>
- *def\_visitor* operator[](CallPolicies const& policies) const;
- };
- .. @ignore()
- ``init`` requirements
- ~~~~~~~~~~~~~~~~~~~~~
- * ``ParameterSpecs`` is an `MPL sequence`_ where each element is a
- model of |ParameterSpec|.
- * For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity
- range** of ``ParameterSpecs``, ``Class`` must support these
- expressions:
- ======================= ============= =========================================
- Expression Return type Requirements
- ======================= ============= =========================================
- ``Class(a0, …, aN)`` \- ``a0``\ …\ ``aN`` are tagged arguments.
- ======================= ============= =========================================
- ``template <class CallPolicies> operator[](CallPolicies const&)``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Returns a ``def_visitor`` equivalent to ``*this``, except that it
- uses CallPolicies when creating the binding.
- Example
- ~~~~~~~
- .. parsed-literal::
- #include <boost/parameter/keyword.hpp>
- #include <boost/parameter/preprocessor.hpp>
- #include <boost/parameter/python.hpp>
- #include <boost/python.hpp>
- #include <boost/mpl/vector.hpp>
- BOOST_PARAMETER_KEYWORD(tag, x)
- BOOST_PARAMETER_KEYWORD(tag, y)
- struct base
- {
- template <class ArgumentPack>
- base(ArgumentPack const& args)
- {
- *… use args …*
- }
- };
- class X : base
- {
- public:
- BOOST_PARAMETER_CONSTRUCTOR(X, (base), tag,
- (required (x, \*))
- (optional (y, \*))
- )
- };
- BOOST_PYTHON_MODULE(*module name*)
- {
- using namespace boost::python;
- namespace py = boost::parameter::python;
- namespace mpl = boost::mpl;
- class_<X>("X", no_init)
- .def(
- py::init<
- mpl::vector<tag::x(int), tag::y\*(int)>
- >()
- );
- }
- .. @example.replace_emphasis('''
- assert(args[x] == 0);
- assert(args[y | 1] == 1);
- ''')
- .. @example.replace_emphasis('my_module')
- .. @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'
- )
- ------------------------------------------------------------------------------
- class template ``call``
- -----------------------
- Defines a ``__call__`` operator, mapped to ``operator()`` in C++.
- .. parsed-literal::
- template <class ParameterSpecs>
- struct call : python::def_visitor<call<ParameterSpecs> >
- {
- template <class Class>
- void def(Class& class\_);
- template <class CallPolicies>
- *def\_visitor* operator[](CallPolicies const& policies) const;
- };
- .. @ignore()
- ``call`` requirements
- ~~~~~~~~~~~~~~~~~~~~~
- * ``ParameterSpecs`` is an `MPL sequence`_ where each element
- except the first models |ParameterSpec|. The first element
- is the result type of ``c(…)``.
- * ``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 ``ParameterSpecs``.
- ``template <class CallPolicies> operator[](CallPolicies const&)``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Returns a ``def_visitor`` equivalent to ``*this``, except that it
- uses CallPolicies when creating the binding.
- Example
- ~~~~~~~
- .. parsed-literal::
- #include <boost/parameter/keyword.hpp>
- #include <boost/parameter/preprocessor.hpp>
- #include <boost/parameter/python.hpp>
- #include <boost/python.hpp>
- #include <boost/mpl/vector.hpp>
- BOOST_PARAMETER_KEYWORD(tag, x)
- BOOST_PARAMETER_KEYWORD(tag, y)
- namespace parameter = boost::parameter;
- typedef parameter::parameters<
- parameter::required<tag::x>
- , parameter::optional<tag::y>
- > call_parameters;
- class X
- {
- public:
- template <class ArgumentPack>
- int call_impl(ArgumentPack const& args)
- {
- *… use 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(*module name*)
- {
- using namespace boost::python;
- namespace py = parameter::python;
- namespace mpl = boost::mpl;
- class_<X>("X")
- .def(
- py::call<
- mpl::vector<int, tag::x(int), tag::y\*(int)>
- >()
- );
- }
- .. @example.replace_emphasis('''
- assert(args[x] == 0);
- assert(args[y | 1] == 1);
- return 0;
- ''')
- .. @example.replace_emphasis('my_module')
- .. @my_module = build(
- output = 'my_module'
- , target_rule = 'python-extension'
- , input = '/boost/python//boost_python'
- )
- ------------------------------------------------------------------------------
- class template ``function``
- ---------------------------
- Defines a named parameter enabled member function.
- .. parsed-literal::
- template <class Fwd, class ParameterSpecs>
- struct function : python::def_visitor<function<Fwd, ParameterSpecs> >
- {
- template <class Class, class Options>
- void def(Class& class\_, char const* name, Options const& options);
- };
- .. @ignore()
- ``function`` requirements
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- * ``ParameterSpecs`` is an `MPL sequence`_ where each element
- except the first models |ParameterSpec|. The first element
- is the result type of ``c.f(…)``, where ``f`` is the member
- function.
- * 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 ``ParameterSpecs``.
- Example
- ~~~~~~~
- This example exports a member function ``f(int x, int y = …)`` to Python. The
- sequence of |ParameterSpec|'s ``mpl::vector2<tag::x(int), tag::y*(int)>`` has
- an **arity range** of [2,2], so we only need one forwarding overload.
- .. parsed-literal::
- #include <boost/parameter/keyword.hpp>
- #include <boost/parameter/preprocessor.hpp>
- #include <boost/parameter/python.hpp>
- #include <boost/python.hpp>
- #include <boost/mpl/vector.hpp>
- BOOST_PARAMETER_KEYWORD(tag, x)
- BOOST_PARAMETER_KEYWORD(tag, y)
- class X
- {
- public:
- BOOST_PARAMETER_MEMBER_FUNCTION((void), f, tag,
- (required (x, \*))
- (optional (y, \*, 1))
- )
- {
- *…*
- }
- };
- 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(*module name*)
- {
- using namespace boost::python;
- namespace py = boost::parameter::python;
- namespace mpl = boost::mpl;
- class_<X>("X")
- .def("f",
- py::function<
- f_fwd
- , mpl::vector<void, tag::x(int), tag::y\*(int)>
- >()
- );
- }
- .. @example.replace_emphasis('''
- assert(x == 0);
- assert(y == 1);
- ''')
- .. @example.replace_emphasis('my_module')
- .. @my_module = build(
- output = 'my_module'
- , target_rule = 'python-extension'
- , input = '/boost/python//boost_python'
- )
- ------------------------------------------------------------------------------
- function template ``def``
- -------------------------
- Defines a named parameter enabled free function in the current Python scope.
- .. parsed-literal::
- template <class Fwd, class ParameterSpecs>
- void def(char const* name);
- .. @ignore()
- ``def`` requirements
- ~~~~~~~~~~~~~~~~~~~~
- * ``ParameterSpecs`` is an `MPL sequence`_ where each element
- except the first models |ParameterSpec|. The first element
- is the result type of ``f(…)``, where ``f`` is the function.
- * 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 ``ParameterSpecs``.
- Example
- ~~~~~~~
- This example exports a function ``f(int x, int y = …)`` to Python. The
- sequence of |ParameterSpec|'s ``mpl::vector2<tag::x(int), tag::y*(int)>`` 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, \*, 1))
- )
- {
- *…*
- }
- 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::vector<
- void, tag::\ x(int), tag::\ y\*(int)
- >
- >("f");
- }
- .. @ignore()
- .. again, the undefined ``fwd`` identifier.
- Portability
- -----------
- The Boost.Parameter Python binding library requires *partial template
- specialization*.
|