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$ 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 779