Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/parameter/doc/python.rst @ 30

Last change on this file since 30 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 22.3 KB
RevLine 
[29]1+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 The Boost Parameter Library Python Binding Documentation
3+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4
5:Authors:       Daniel Wallin
6:Contact:       dalwan01@student.umu.se
7:organization:  `Boost Consulting`_
8:date:          $Date: 2006/09/21 17:33:28 $
9
10:copyright:     Copyright David Abrahams, Daniel Wallin
11                2005. Distributed under the Boost Software License,
12                Version 1.0. (See accompanying file LICENSE_1_0.txt
13                or copy at http://www.boost.org/LICENSE_1_0.txt)
14
15:abstract:      Makes it possible to bind Boost.Parameter-enabled
16                functions, operators and constructors to Python.
17
18|(logo)|__
19
20.. |(logo)| image:: ../../../../boost.png
21   :alt: Boost
22
23__ ../../../../index.htm
24
25.. _`Boost Consulting`: http://www.boost-consulting.com
26
27
28.. role:: class
29    :class: class
30
31.. role:: concept
32    :class: concept
33
34.. role:: function
35    :class: function
36
37.. |ParameterSpec| replace:: :concept:`ParameterSpec`
38
39.. contents::
40    :depth: 1
41
42Introduction
43------------
44
45``boost/parameter/python.hpp`` introduces a group of |def_visitors|_ that can
46be used to easily expose Boost.Parameter-enabled member functions to Python with
47Boost.Python. It also provides a function template ``def()`` that can be used
48to expose Boost.Parameter-enabled free functions.
49
50.. |def_visitor| replace:: ``def_visitor``
51.. |def_visitors| replace:: ``def_visitors``
52
53.. _def_visitor: def_visitors_
54.. _def_visitors: ../../../python/doc/v2/def_visitor.html
55
56When binding a Boost.Parameter enabled function, the keyword tags
57must be specified.  Additionally, because Boost.Parameter enabled
58functions are templates, the desired function signature must be
59specified.
60
61..  The keyword tags are specified as an `MPL Sequence`_, using the
62    pointer qualifications described in |ParameterSpec|_ below.  The
63    signature is also specifid as an `MPL sequence`_ of parameter
64    types. Additionally, ``boost::parameter::python::function`` and
65    ``boost::parameter::python::def`` requires a class with forwarding
66    overloads. We will take a closer look at how this is done in the
67    tutorial section below.
68
69The keyword tags and associated argument types are specified as an `MPL
70Sequence`_, using the function type syntax described in |ParameterSpec|_
71below. Additionally, ``boost::parameter::python::function`` and
72``boost::parameter::python::def`` requires a class with forwarding overloads.
73We will take a closer look at how this is done in the tutorial section below.
74
75.. The last two sentences are terribly vague.  Which namespace is
76.. ``function`` in?  Isn't the return type always needed?  What
77.. else are we going to do other than pass these sequences to
78.. function?
79
80.. _`MPL Sequence`: ../../../mpl/doc/refmanual/sequences.html
81.. _parameterspec: `concept ParameterSpec`_
82
83Tutorial
84--------
85
86In this section we will outline the steps needed to bind a simple
87Boost.Parameter-enabled member function to Python. Knowledge of the
88Boost.Parameter macros_ are required to understand this section.
89
90.. _macros: index.html
91
92The class and member function we are interested in binding looks
93like this:
94
95.. parsed-literal::
96
97  #include <boost/parameter/keyword.hpp>
98  #include <boost/parameter/preprocessor.hpp>
99  #include <boost/parameter/python.hpp>
100  #include <boost/python.hpp>
101
102  // First the keywords
103  BOOST_PARAMETER_KEYWORD(tag, title)
104  BOOST_PARAMETER_KEYWORD(tag, width)
105  BOOST_PARAMETER_KEYWORD(tag, height)
106
107  class window
108  {
109  public:
110      BOOST_PARAMETER_MEMBER_FUNCTION(
111        (void), open, tag,
112        (required (title, (std::string)))
113        (optional (width, (unsigned), 400)
114                  (height, (unsigned), 400))
115      )
116      {
117          *… function implementation …*
118      }
119  };
120
121.. @example.prepend('#include <cassert>')
122.. @example.replace_emphasis('''
123   assert(title == "foo");
124   assert(height == 20);
125   assert(width == 400);
126   ''')
127
128It defines a set of overloaded member functions called ``open`` with one
129required parameter and two optional ones. To bind this member function to
130Python we use the binding utility ``boost::parameter::python::function``.
131``boost::parameter::python::function`` is a |def_visitor|_ that we'll instantiate
132and pass to ``boost::python::class_::def()``.
133
134To use ``boost::parameter::python::function`` we first need to define
135a class with forwarding overloads.
136
137::
138
139  struct open_fwd
140  {
141      template <class A0, class A1, class A2>
142      void operator()(
143          boost::type<void>, window& self
144        , A0 const& a0, A1 const& a1, A2 const& a2
145      )
146      {
147          self.open(a0, a1, a2);
148      }
149  };
150
151The first parameter, ``boost::type<void>``, tells the forwarding overload
152what the return type should be. In this case we know that it's always void
153but in some cases, when we are exporting several specializations of a
154Boost.Parameter-enabled template, we need to use that parameter to
155deduce the return type.
156
157``window::open()`` takes a total of 3 parameters, so the forwarding function
158needs to take three parameters as well.
159
160.. Note::
161
162    We only need one overload in the forwarding class, despite the
163    fact that there are two optional parameters. There are special
164    circumstances when several overload are needed; see
165    `special keywords`_.
166
167Next we'll define the module and export the class:
168
169::
170
171  BOOST_PYTHON_MODULE(my_module)
172  {
173      using namespace boost::python;
174      namespace py = boost::parameter::python;
175      namespace mpl = boost::mpl;
176
177      class_<window>("window")
178          .def(
179              "open", py::function<
180                  open_fwd
181                , mpl::vector<
182                      void
183                    , tag::title(std::string)
184                    , tag::width*(unsigned)
185                    , tag::height*(unsigned)
186                  >
187              >()
188          );
189  }
190
191.. @jam_prefix.append('import python ;')
192.. @jam_prefix.append('stage . : my_module /boost/python//boost_python ;')
193.. @my_module = build(
194        output = 'my_module'
195      , target_rule = 'python-extension'
196      , input = '/boost/python//boost_python'
197      , howmany = 'all'
198    )
199
200.. @del jam_prefix[:]
201
202``py::function`` is passed two parameters. The first one is the class with
203forwarding overloads that we defined earlier. The second one is an `MPL
204Sequence`_ with the keyword tag types and argument types for the function
205specified as function types. The pointer syntax used in ``tag::width*`` and
206``tag::height*`` means that the parameter is optional. The first element of
207the `MPL Sequence`_ is the return type of the function, in this case ``void``.
208
209..  The
210    pointer syntax means that the parameter is optional, so in this case
211    ``width`` and ``height`` are optional parameters. The third parameter
212    is an `MPL Sequence`_ with the desired function signature. The return type comes first, and
213    then the parameter types:
214
215    .. parsed-literal::
216
217        mpl::vector<void,        std::string, unsigned, unsigned>
218                    *return type*  *title*        *width*     *height*
219
220    .. @ignore()
221
222That's it! This class can now be used in Python with the expected syntax::
223
224    >>> w = my_module.window()
225    >>> w.open(title = "foo", height = 20)
226
227.. @example.prepend('import my_module')
228.. @run_python(module_path = my_module)
229
230.. Sorry to say this at such a late date, but this syntax really
231.. strikes me as cumbersome.  Couldn't we do something like:
232
233    class_<window>("window")
234          .def(
235              "open",
236              (void (*)(
237                  tag::title(std::string),
238                  tag::width*(unsigned),
239                  tag::height*(unsigned))
240              )0
241          );
242
243   or at least:
244
245      class_<window>("window")
246          .def(
247              "open",
248              mpl::vector<
249                  void,
250                  tag::title(std::string),
251                  tag::width*(unsigned),
252                  tag::height*(unsigned)
253              >()
254          );
255
256   assuming, that is, that we will have to repeat the tags (yes,
257   users of broken compilers will have to give us function pointer
258   types instead).
259
260------------------------------------------------------------------------------
261
262concept |ParameterSpec|
263-----------------------
264
265A |ParameterSpec| is a function type ``K(T)`` that describes both the keyword tag,
266``K``, and the argument type, ``T``, for a parameter.
267
268``K`` is either:
269
270* A *required* keyword of the form ``Tag``
271* **or**, an *optional* keyword of the form ``Tag*``
272* **or**, a *special* keyword of the form ``Tag**``
273
274where ``Tag`` is a keyword tag type, as used in a specialization
275of |keyword|__.
276
277.. |keyword| replace:: ``boost::parameter::keyword``
278__ ../../../parameter/doc/html/reference.html#keyword
279
280The **arity range** for an `MPL Sequence`_ of |ParameterSpec|'s is
281defined as the closed range:
282
283.. parsed-literal::
284
285  [ mpl::size<S> - number of *special* keyword tags in ``S``, mpl::size<S> ]
286
287For example, the **arity range** of ``mpl::vector2<x(int),y(int)>`` is ``[2,2]``,
288the **arity range** of ``mpl::vector2<x(int),y*(int)>`` is ``[2,2]`` and the
289**arity range** of ``mpl::vector2<x(int),y**(int)>`` is ``[1,2]``.
290
291
292
293*special* keywords
294---------------------------------
295
296Sometimes it is desirable to have a default value for a parameter that differ
297in type from the parameter. This technique is useful for doing simple tag-dispatching
298based on the presence of a parameter. An example_ of this is given in the Boost.Parameter
299docs. The example uses a different technique, but could also have been written like this:
300
301.. parsed-literal::
302
303  namespace core
304  {
305    template <class ArgumentPack>
306    void dfs_dispatch(ArgumentPack const& args, mpl::false\_)
307    {
308        *…compute and use default color map…*
309    }
310
311    template <class ArgumentPack, class ColorMap>
312    void dfs_dispatch(ArgumentPack const& args, ColorMap colormap)
313    {
314        *…use colormap…*
315    }
316  }
317
318  template <class ArgumentPack>
319  void depth_first_search(ArgumentPack const& args)
320  {
321      core::dfs_dispatch(args, args[color | mpl::false_()]);
322  }
323
324.. @example.prepend('''
325   #include <boost/parameter/keyword.hpp>
326   #include <boost/parameter/parameters.hpp>
327   #include <boost/mpl/bool.hpp>
328   #include <cassert>
329
330   BOOST_PARAMETER_KEYWORD(tag, color);
331
332   typedef boost::parameter::parameters<tag::color> params;
333
334   namespace mpl = boost::mpl;
335   ''')
336
337.. @example.replace_emphasis('''
338   assert(args[color | 1] == 1);
339   ''')
340
341.. @example.replace_emphasis('''
342   assert(args[color | 1] == 0);
343   ''')
344
345.. @example.append('''
346   int main()
347   {
348       depth_first_search(params()());
349       depth_first_search(params()(color = 0));
350   }''')
351
352.. @build()
353
354.. _example: index.html#dispatching-based-on-the-presence-of-a-default
355
356In the above example the type of the default for ``color`` is ``mpl::false_``, a
357type that is distinct from any color map that the user might supply.
358
359When binding the case outlined above, the default type for ``color`` will not
360be convertible to the parameter type. Therefore we need to tag the ``color``
361keyword as a *special* keyword. By doing this we tell the binding functions
362that it needs to generate two overloads, one with the ``color`` parameter
363present and one without. Had there been two *special* keywords, four
364overloads would need to be generated. The number of generated overloads is
365equal to 2\ :sup:`N`, where ``N`` is the number of *special* keywords.
366
367------------------------------------------------------------------------------
368
369class template ``init``
370-----------------------
371
372Defines a named parameter enabled constructor.
373
374.. parsed-literal::
375
376    template <class ParameterSpecs>
377    struct init : python::def_visitor<init<ParameterSpecs> >
378    {
379        template <class Class>
380        void def(Class& class\_);
381
382        template <class CallPolicies>
383        *def\_visitor* operator[](CallPolicies const& policies) const;
384    };
385
386.. @ignore()
387
388``init`` requirements
389~~~~~~~~~~~~~~~~~~~~~
390
391* ``ParameterSpecs`` is an `MPL sequence`_ where each element is a
392  model of |ParameterSpec|.
393* For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity
394  range** of ``ParameterSpecs``, ``Class`` must support these
395  expressions:
396
397  ======================= ============= =========================================
398  Expression              Return type   Requirements
399  ======================= ============= =========================================
400  ``Class(a0, …, aN)``    \-            ``a0``\ …\ ``aN`` are tagged arguments.
401  ======================= ============= =========================================
402
403
404
405``template <class CallPolicies> operator[](CallPolicies const&)``
406~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
407
408Returns a ``def_visitor`` equivalent to ``*this``, except that it
409uses CallPolicies when creating the binding.
410
411
412Example
413~~~~~~~
414
415.. parsed-literal::
416
417    #include <boost/parameter/keyword.hpp>
418    #include <boost/parameter/preprocessor.hpp>
419    #include <boost/parameter/python.hpp>
420    #include <boost/python.hpp>
421    #include <boost/mpl/vector.hpp>
422
423    BOOST_PARAMETER_KEYWORD(tag, x)
424    BOOST_PARAMETER_KEYWORD(tag, y)
425
426    struct base
427    {
428        template <class ArgumentPack>
429        base(ArgumentPack const& args)
430        {
431            *… use args …*
432        }
433    };
434
435    class X : base
436    {
437    public:
438        BOOST_PARAMETER_CONSTRUCTOR(X, (base), tag,
439            (required (x, \*))
440            (optional (y, \*))
441        )
442    };
443
444    BOOST_PYTHON_MODULE(*module name*)
445    {
446        using namespace boost::python;
447        namespace py = boost::parameter::python;
448        namespace mpl = boost::mpl;
449
450        class_<X>("X", no_init)
451            .def(
452                py::init<
453                    mpl::vector<tag::x(int), tag::y\*(int)>
454                >()
455            );
456    }
457
458.. @example.replace_emphasis('''
459   assert(args[x] == 0);
460   assert(args[y | 1] == 1);
461   ''')
462
463.. @example.replace_emphasis('my_module')
464
465.. @jam_prefix.append('import python ;')
466.. @jam_prefix.append('stage . : my_module /boost/python//boost_python ;')
467.. @my_module = build(
468        output = 'my_module'
469      , target_rule = 'python-extension'
470      , input = '/boost/python//boost_python'
471    )
472
473------------------------------------------------------------------------------
474
475class template ``call``
476-----------------------
477
478Defines a ``__call__`` operator, mapped to ``operator()`` in C++.
479
480.. parsed-literal::
481
482    template <class ParameterSpecs>
483    struct call : python::def_visitor<call<ParameterSpecs> >
484    {
485        template <class Class>
486        void def(Class& class\_);
487
488        template <class CallPolicies>
489        *def\_visitor* operator[](CallPolicies const& policies) const;
490    };
491
492.. @ignore()
493
494``call`` requirements
495~~~~~~~~~~~~~~~~~~~~~
496
497* ``ParameterSpecs`` is an `MPL sequence`_ where each element
498  except the first models |ParameterSpec|. The first element
499  is the result type of ``c(…)``.
500* ``Class`` must support these expressions, where ``c`` is an
501  instance of ``Class``:
502
503  =================== ==================== =======================================
504  Expression          Return type          Requirements
505  =================== ==================== =======================================
506  ``c(a0, …, aN)``    Convertible to ``R`` ``a0``\ …\ ``aN`` are tagged arguments.
507  =================== ==================== =======================================
508
509  For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``ParameterSpecs``.
510
511
512``template <class CallPolicies> operator[](CallPolicies const&)``
513~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
514
515Returns a ``def_visitor`` equivalent to ``*this``, except that it
516uses CallPolicies when creating the binding.
517
518
519Example
520~~~~~~~
521
522.. parsed-literal::
523
524    #include <boost/parameter/keyword.hpp>
525    #include <boost/parameter/preprocessor.hpp>
526    #include <boost/parameter/python.hpp>
527    #include <boost/python.hpp>
528    #include <boost/mpl/vector.hpp>
529
530    BOOST_PARAMETER_KEYWORD(tag, x)
531    BOOST_PARAMETER_KEYWORD(tag, y)
532
533    namespace parameter = boost::parameter;
534
535    typedef parameter::parameters<
536        parameter::required<tag::x>
537      , parameter::optional<tag::y>
538    > call_parameters;
539
540    class X
541    {
542    public:
543        template <class ArgumentPack>
544        int call_impl(ArgumentPack const& args)
545        {
546            *… use args …*
547        }
548
549        template <class A0>
550        int operator()(A0 const& a0)
551        {
552            return call_impl(call_parameters()(a0));
553        }
554
555        template <class A0, class A1>
556        int operator()(A0 const& a0, A1 const& a1)
557        {
558            return call_impl(call_parameters()(a0,a1));
559        }
560    };
561
562    BOOST_PYTHON_MODULE(*module name*)
563    {
564        using namespace boost::python;
565        namespace py = parameter::python;
566        namespace mpl = boost::mpl;
567
568        class_<X>("X")
569            .def(
570                py::call<
571                    mpl::vector<int, tag::x(int), tag::y\*(int)>
572                >()
573            );
574    }   
575
576.. @example.replace_emphasis('''
577   assert(args[x] == 0);
578   assert(args[y | 1] == 1);
579   return 0;
580   ''')
581
582.. @example.replace_emphasis('my_module')
583
584.. @my_module = build(
585        output = 'my_module'
586      , target_rule = 'python-extension'
587      , input = '/boost/python//boost_python'
588    )
589
590------------------------------------------------------------------------------
591
592class template ``function``
593---------------------------
594
595Defines a named parameter enabled member function.
596
597.. parsed-literal::
598
599    template <class Fwd, class ParameterSpecs>
600    struct function : python::def_visitor<function<Fwd, ParameterSpecs> >
601    {
602        template <class Class, class Options>
603        void def(Class& class\_, char const* name, Options const& options);
604    };
605
606.. @ignore()
607
608``function`` requirements
609~~~~~~~~~~~~~~~~~~~~~~~~~
610
611* ``ParameterSpecs`` is an `MPL sequence`_ where each element
612  except the first models |ParameterSpec|. The first element
613  is the result type of ``c.f(…)``, where ``f`` is the member
614  function.
615* An instance of ``Fwd`` must support this expression:
616
617  ============================================ ==================== =================================================
618  Expression                                   Return type          Requirements
619  ============================================ ==================== =================================================
620  ``fwd(boost::type<R>(), self, a0, …, aN)``   Convertible to ``R`` ``self`` is a reference to the object on which
621                                                                    the function should be invoked. ``a0``\ …\ ``aN``
622                                                                    are tagged arguments.
623  ============================================ ==================== =================================================
624
625  For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``ParameterSpecs``.
626
627
628Example
629~~~~~~~
630
631This example exports a member function ``f(int x, int y = …)`` to Python. The
632sequence of |ParameterSpec|'s ``mpl::vector2<tag::x(int), tag::y*(int)>`` has
633an **arity range** of [2,2], so we only need one forwarding overload.
634
635.. parsed-literal::
636
637    #include <boost/parameter/keyword.hpp>
638    #include <boost/parameter/preprocessor.hpp>
639    #include <boost/parameter/python.hpp>
640    #include <boost/python.hpp>
641    #include <boost/mpl/vector.hpp>
642
643    BOOST_PARAMETER_KEYWORD(tag, x)
644    BOOST_PARAMETER_KEYWORD(tag, y)
645
646    class X
647    {
648    public:
649        BOOST_PARAMETER_MEMBER_FUNCTION((void), f, tag,
650            (required (x, \*))
651            (optional (y, \*, 1))
652        )
653        {
654            *…*
655        }
656    };
657
658    struct f_fwd
659    {
660        template <class A0, class A1>
661        void operator()(boost::type<void>, X& self, A0 const& a0, A1 const& a1)
662        {
663            self.f(a0, a1);
664        }
665    };
666
667    BOOST_PYTHON_MODULE(*module name*)
668    {
669        using namespace boost::python;
670        namespace py = boost::parameter::python;
671        namespace mpl = boost::mpl;
672
673        class_<X>("X")
674            .def("f",
675                py::function<
676                    f_fwd
677                  , mpl::vector<void, tag::x(int), tag::y\*(int)>
678                >()
679            );
680    }
681
682.. @example.replace_emphasis('''
683   assert(x == 0);
684   assert(y == 1);
685   ''')
686
687.. @example.replace_emphasis('my_module')
688
689.. @my_module = build(
690        output = 'my_module'
691      , target_rule = 'python-extension'
692      , input = '/boost/python//boost_python'
693    )
694
695------------------------------------------------------------------------------
696
697function template ``def``
698-------------------------
699
700Defines a named parameter enabled free function in the current Python scope.
701
702.. parsed-literal::
703
704    template <class Fwd, class ParameterSpecs>
705    void def(char const* name);
706
707.. @ignore()
708
709``def`` requirements
710~~~~~~~~~~~~~~~~~~~~
711
712* ``ParameterSpecs`` is an `MPL sequence`_ where each element
713  except the first models |ParameterSpec|. The first element
714  is the result type of ``f(…)``, where ``f`` is the function.
715* An instance of ``Fwd`` must support this expression:
716
717  ====================================== ==================== =======================================
718  Expression                             Return type          Requirements
719  ====================================== ==================== =======================================
720  ``fwd(boost::type<R>(), a0, …, aN)``   Convertible to ``R`` ``a0``\ …\ ``aN`` are tagged arguments.
721  ====================================== ==================== =======================================
722
723  For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``ParameterSpecs``.
724
725
726Example
727~~~~~~~
728
729This example exports a function ``f(int x, int y = …)`` to Python. The
730sequence of |ParameterSpec|'s ``mpl::vector2<tag::x(int), tag::y*(int)>`` has
731an **arity range** of [2,2], so we only need one forwarding overload.
732
733.. parsed-literal::
734
735    BOOST_PARAMETER_FUNCTION((void), f, tag,
736        (required (x, \*))
737        (optional (y, \*, 1))
738    )
739    {
740        *…*
741    }
742
743    struct f_fwd
744    {
745        template <class A0, class A1>
746        void operator()(boost::type<void>, A0 const& a0, A1 const& a1)
747        {
748            f(a0, a1);
749        }
750    };
751
752    BOOST_PYTHON_MODULE(…)
753    {
754        def<
755            f_fwd
756          , mpl::vector<
757                void, tag::\ x(int), tag::\ y\*(int)
758            >
759        >("f");
760    }
761
762.. @ignore()
763
764.. again, the undefined ``fwd`` identifier.
765
766Portability
767-----------
768
769The Boost.Parameter Python binding library requires *partial template
770specialization*.
771
Note: See TracBrowser for help on using the repository browser.