+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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: .. parsed-literal:: #include #include #include #include // 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)) ) { *…* } }; .. @example.prepend('#include ') .. @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. :: struct open_fwd { template void operator()( boost::type, window& self, A0 const& a0, A1 const& a1, A2 const& a2 ) { self.open(a0, a1, a2); } }; The first parameter, ``boost::type``, 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") .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 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 *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") .def( "open", (void (*)( tag::title(std::string), tag::width*(unsigned), tag::height*(unsigned)) )0 ); or at least: class_("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 - number of *special* keyword tags in ``S`` , mpl::size ] .. @ignore() For example, the **arity range** of ``mpl::vector2`` is [2,2], the **arity range** of ``mpl::vector2`` is [2,2] and the **arity range** of ``mpl::vector2`` 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:: namespace core { template void dfs_dispatch(ArgumentPack const& args, mpl::false\_) { *…compute and use default color map…* } template void dfs_dispatch(ArgumentPack const& args, ColorMap colormap) { *…use colormap…* } } template void depth_first_search(ArgumentPack const& args) { core::dfs_dispatch(args, args[color | mpl::false_()]); } .. @example.prepend(''' #include #include #include #include BOOST_PARAMETER_KEYWORD(tag, color); typedef boost::parameter::parameters 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. 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 struct init : python::def_visitor > { template void def(Class& class\_); }; .. @ignore() ``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:: #include #include #include #include #include BOOST_PARAMETER_KEYWORD(tag, x) BOOST_PARAMETER_KEYWORD(tag, y) struct base { template 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", no_init) .def( py::init< mpl::vector >() ); } .. @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 struct call : python::def_visitor > { template void def(Class& class\_); }; .. @ignore() ``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:: #include #include #include #include #include BOOST_PARAMETER_KEYWORD(tag, x) BOOST_PARAMETER_KEYWORD(tag, y) namespace parameter = boost::parameter; typedef parameter::parameters< parameter::required , parameter::optional > call_parameters; class X { public: template int call_impl(ArgumentPack const& args) { *…use args…* } template int operator()(A0 const& a0) { return call_impl(call_parameters()(a0)); } template 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") .def( py::call< mpl::vector >() ); } .. @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 struct function : python::def_visitor > { template void def(Class& class\_, char const* name, Options const& options); }; .. @ignore() ``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(), 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`` has an **arity range** of [2,2], so we only need one forwarding overload. .. parsed-literal:: #include #include #include #include #include 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 void operator()(boost::type, 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") .def("f", py::function< f_fwd , mpl::vector >() ); } .. @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 void def(char const* name); .. @ignore() ``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(), 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`` 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 void operator()(boost::type, 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*.