PageRenderTime 41ms CodeModel.GetById 18ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/libs/parameter/doc/python.rst

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