]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | +++++++++++++++++++++++++++++++++++++++++++++++++ |
2 | The Boost Parameter Library | |
3 | +++++++++++++++++++++++++++++++++++++++++++++++++ | |
4 | ||
5 | |(logo)|__ | |
6 | ||
7 | .. |(logo)| image:: ../../../../boost.png | |
8 | :alt: Boost | |
9 | ||
10 | __ ../../../../index.htm | |
11 | ||
12 | ------------------------------------- | |
13 | ||
14 | :Abstract: Use this library to write functions and class templates | |
15 | that can accept arguments by name: | |
16 | ||
17 | .. parsed-literal:: | |
18 | ||
19 | new_window("alert", **_width=10**, **_titlebar=false**); | |
20 | ||
21 | smart_ptr< | |
22 | Foo | |
23 | , **deleter<Deallocate<Foo> >** | |
24 | , **copy_policy<DeepCopy>** > p(new Foo); | |
25 | ||
26 | Since named arguments can be passed in any order, they are | |
27 | especially useful when a function or template has more than one | |
28 | parameter with a useful default value. The library also supports | |
29 | *deduced* parameters; that is to say, parameters whose identity | |
30 | can be deduced from their types. | |
31 | ||
32 | .. @jam_prefix.append(''' | |
33 | project test : requirements <include>. <implicit-dependency>/boost//headers ;''') | |
34 | ||
35 | .. @example.prepend(''' | |
36 | #include <boost/parameter.hpp> | |
37 | ||
38 | namespace test | |
39 | { | |
40 | BOOST_PARAMETER_NAME(title) | |
41 | BOOST_PARAMETER_NAME(width) | |
42 | BOOST_PARAMETER_NAME(titlebar) | |
43 | ||
44 | BOOST_PARAMETER_FUNCTION( | |
45 | (int), new_window, tag, (required (title,*)(width,*)(titlebar,*))) | |
46 | { | |
47 | return 0; | |
48 | } | |
49 | ||
50 | BOOST_PARAMETER_TEMPLATE_KEYWORD(deleter) | |
51 | BOOST_PARAMETER_TEMPLATE_KEYWORD(copy_policy) | |
52 | ||
53 | template <class T> struct Deallocate {}; | |
54 | struct DeepCopy {}; | |
55 | ||
56 | namespace parameter = boost::parameter; | |
57 | ||
58 | struct Foo {}; | |
59 | template <class T, class A0, class A1> | |
60 | struct smart_ptr | |
61 | { | |
62 | smart_ptr(Foo*); | |
63 | }; | |
64 | } | |
65 | using namespace test; | |
66 | int x = '''); | |
67 | ||
68 | .. @test('compile') | |
69 | ||
70 | ||
71 | ------------------------------------- | |
72 | ||
73 | :Authors: David Abrahams, Daniel Wallin | |
74 | :Contact: dave@boost-consulting.com, daniel@boostpro.com | |
75 | :organization: `BoostPro Computing`_ | |
76 | :date: $Date: 2005/07/17 19:53:01 $ | |
77 | ||
78 | :copyright: Copyright David Abrahams, Daniel Wallin | |
79 | 2005-2009. Distributed under the Boost Software License, | |
80 | Version 1.0. (See accompanying file LICENSE_1_0.txt | |
81 | or copy at http://www.boost.org/LICENSE_1_0.txt) | |
82 | ||
83 | .. _`BoostPro Computing`: http://www.boostpro.com | |
84 | ||
85 | .. _concepts: http://www.boost.org/more/generic_programming.html#concept | |
86 | ||
87 | ------------------------------------- | |
88 | ||
89 | [Note: this tutorial does not cover all details of the library. Please see also the `reference documentation`__\ ] | |
90 | ||
91 | __ reference.html | |
92 | ||
93 | .. contents:: **Table of Contents** | |
94 | :depth: 2 | |
95 | ||
96 | .. role:: concept | |
97 | :class: concept | |
98 | ||
99 | .. role:: vellipsis | |
100 | :class: vellipsis | |
101 | ||
102 | .. section-numbering:: | |
103 | ||
104 | ------------------------------------- | |
105 | ||
106 | ============ | |
107 | Motivation | |
108 | ============ | |
109 | ||
110 | In C++, arguments_ are normally given meaning by their positions | |
111 | with respect to a parameter_ list: the first argument passed maps | |
112 | onto the first parameter in a function's definition, and so on. | |
113 | That protocol is fine when there is at most one parameter with a | |
114 | default value, but when there are even a few useful defaults, the | |
115 | positional interface becomes burdensome: | |
116 | ||
117 | * .. compound:: | |
118 | ||
119 | Since an argument's meaning is given by its position, we have to | |
120 | choose an (often arbitrary) order for parameters with default | |
121 | values, making some combinations of defaults unusable: | |
122 | ||
123 | .. parsed-literal:: | |
124 | ||
125 | window* new_window( | |
126 | char const* name, | |
127 | **int border_width = default_border_width,** | |
128 | bool movable = true, | |
129 | bool initially_visible = true | |
130 | ); | |
131 | ||
132 | const bool movability = false; | |
133 | window* w = new_window("alert box", movability); | |
134 | ||
135 | In the example above we wanted to make an unmoveable window | |
136 | with a default ``border_width``, but instead we got a moveable | |
137 | window with a ``border_width`` of zero. To get the desired | |
138 | effect, we'd need to write: | |
139 | ||
140 | .. parsed-literal:: | |
141 | ||
142 | window* w = new_window( | |
143 | "alert box", **default_border_width**, movability); | |
144 | ||
145 | * .. compound:: | |
146 | ||
147 | It can become difficult for readers to understand the meaning of | |
148 | arguments at the call site:: | |
149 | ||
150 | window* w = new_window("alert", 1, true, false); | |
151 | ||
152 | Is this window moveable and initially invisible, or unmoveable | |
153 | and initially visible? The reader needs to remember the order | |
154 | of arguments to be sure. | |
155 | ||
156 | * The author of the call may not remember the order of the | |
157 | arguments either, leading to hard-to-find bugs. | |
158 | ||
159 | .. @ignore(3) | |
160 | ||
161 | ------------------------- | |
162 | Named Function Parameters | |
163 | ------------------------- | |
164 | ||
165 | .. compound:: | |
166 | ||
167 | This library addresses the problems outlined above by associating | |
168 | each parameter name with a keyword object. Now users can identify | |
169 | arguments by name, rather than by position: | |
170 | ||
171 | .. parsed-literal:: | |
172 | ||
173 | window* w = new_window("alert box", **movable_=**\ false); // OK! | |
174 | ||
175 | .. @ignore() | |
176 | ||
177 | --------------------------- | |
178 | Deduced Function Parameters | |
179 | --------------------------- | |
180 | ||
181 | .. compound:: | |
182 | ||
183 | A **deduced parameter** can be passed in any position *without* | |
184 | supplying an explicit parameter name. It's not uncommon for a | |
185 | function to have parameters that can be uniquely identified based | |
186 | on the types of arguments passed. The ``name`` parameter to | |
187 | ``new_window`` is one such example. None of the other arguments, | |
188 | if valid, can reasonably be converted to a ``char const*``. With | |
189 | a deduced parameter interface, we could pass the window name in | |
190 | *any* argument position without causing ambiguity: | |
191 | ||
192 | .. parsed-literal:: | |
193 | ||
194 | window* w = new_window(movable_=false, **"alert box"**); // OK! | |
195 | window* w = new_window(**"alert box"**, movable_=false); // OK! | |
196 | ||
197 | Appropriately used, a deduced parameter interface can free the | |
198 | user of the burden of even remembering the formal parameter | |
199 | names. | |
200 | ||
201 | .. @ignore() | |
202 | ||
203 | -------------------------------- | |
204 | Class Template Parameter Support | |
205 | -------------------------------- | |
206 | ||
207 | .. compound:: | |
208 | ||
209 | The reasoning we've given for named and deduced parameter | |
210 | interfaces applies equally well to class templates as it does to | |
211 | functions. Using the Parameter library, we can create interfaces | |
212 | that allow template arguments (in this case ``shared`` and | |
213 | ``Client``) to be explicitly named, like this: | |
214 | ||
215 | .. parsed-literal:: | |
216 | ||
217 | smart_ptr<**ownership<shared>**, **value_type<Client>** > p; | |
218 | ||
219 | The syntax for passing named template arguments is not quite as | |
220 | natural as it is for function arguments (ideally, we'd be able to | |
221 | write ``smart_ptr<ownership=shared,…>``). This small syntactic | |
222 | deficiency makes deduced parameters an especially big win when | |
223 | used with class templates: | |
224 | ||
225 | .. parsed-literal:: | |
226 | ||
227 | // *p and q could be equivalent, given a deduced* | |
228 | // *parameter interface.* | |
229 | smart_ptr<**shared**, **Client**> p; | |
230 | smart_ptr<**Client**, **shared**> q; | |
231 | ||
232 | .. @ignore(2) | |
233 | ||
234 | ========== | |
235 | Tutorial | |
236 | ========== | |
237 | ||
238 | This tutorial shows all the basics—how to build both named- and deduced-parameter | |
239 | interfaces to function templates and class templates—and several | |
240 | more advanced idioms as well. | |
241 | ||
242 | --------------------------- | |
243 | Parameter-Enabled Functions | |
244 | --------------------------- | |
245 | ||
246 | In this section we'll show how the Parameter library can be used to | |
247 | build an expressive interface to the `Boost Graph library`__\ 's | |
248 | |dfs|_ algorithm. [#old_interface]_ | |
249 | ||
250 | .. Revisit this | |
251 | ||
252 | After laying some groundwork | |
253 | and describing the algorithm's abstract interface, we'll show you | |
254 | how to build a basic implementation with keyword support. Then | |
255 | we'll add support for default arguments and we'll gradually refine the | |
256 | implementation with syntax improvements. Finally we'll show how to | |
257 | streamline the implementation of named parameter interfaces, | |
258 | improve their participation in overload resolution, and optimize | |
259 | their runtime efficiency. | |
260 | ||
261 | __ ../../../graph/index.html | |
262 | ||
263 | .. _dfs: ../../../graph/doc/depth_first_search.html | |
264 | ||
265 | .. |dfs| replace:: ``depth_first_search`` | |
266 | ||
267 | ||
268 | Headers And Namespaces | |
269 | ====================== | |
270 | ||
271 | Most components of the Parameter library are declared in a | |
272 | header named for the component. For example, :: | |
273 | ||
274 | #include <boost/parameter/keyword.hpp> | |
275 | ||
276 | will ensure ``boost::parameter::keyword`` is known to the | |
277 | compiler. There is also a combined header, | |
278 | ``boost/parameter.hpp``, that includes most of the library's | |
279 | components. For the the rest of this tutorial, unless we say | |
280 | otherwise, you can use the rule above to figure out which header | |
281 | to ``#include`` to access any given component of the library. | |
282 | ||
283 | .. @example.append(''' | |
284 | using boost::parameter::keyword; | |
285 | ''') | |
286 | ||
287 | .. @test('compile') | |
288 | ||
289 | Also, the examples below will also be written as if the | |
290 | namespace alias :: | |
291 | ||
292 | namespace parameter = boost::parameter; | |
293 | ||
294 | .. @ignore() | |
295 | ||
296 | has been declared: we'll write ``parameter::xxx`` instead of | |
297 | ``boost::parameter::xxx``. | |
298 | ||
299 | The Abstract Interface to |dfs| | |
300 | =============================== | |
301 | ||
302 | The Graph library's |dfs| algorithm is a generic function accepting | |
303 | from one to four arguments by reference. If all arguments were | |
304 | required, its signature might be as follows:: | |
305 | ||
306 | template < | |
307 | class Graph, class DFSVisitor, class Index, class ColorMap | |
308 | > | |
309 | void depth_first_search( | |
310 | , Graph const& graph | |
311 | , DFSVisitor visitor | |
312 | , typename graph_traits<g>::vertex_descriptor root_vertex | |
313 | , IndexMap index_map | |
314 | , ColorMap& color); | |
315 | ||
316 | .. @ignore() | |
317 | ||
318 | However, most of the parameters have a useful default value, as | |
319 | shown in the table below. | |
320 | ||
321 | .. _`parameter table`: | |
322 | .. _`default expressions`: | |
323 | ||
324 | .. table:: ``depth_first_search`` Parameters | |
325 | ||
326 | +----------------+----------+---------------------------------+----------------------------------+ | |
327 | | Parameter Name | Dataflow | Type | Default Value (if any) | | |
328 | +================+==========+=================================+==================================+ | |
329 | |``graph`` | in |Model of |IncidenceGraph|_ and |none - this argument is required. | | |
330 | | | ||VertexListGraph|_ | | | |
331 | | | | | | | |
332 | +----------------+----------+---------------------------------+----------------------------------+ | |
333 | |``visitor`` | in |Model of |DFSVisitor|_ |``boost::dfs_visitor<>()`` | | |
334 | +----------------+----------+---------------------------------+----------------------------------+ | |
335 | |``root_vertex`` | in |``graph``'s vertex descriptor |``*vertices(graph).first`` | | |
336 | | | |type. | | | |
337 | +----------------+----------+---------------------------------+----------------------------------+ | |
338 | |``index_map`` | in |Model of |ReadablePropertyMap|_ |``get(boost::vertex_index,graph)``| | |
339 | | | |with key type := ``graph``'s | | | |
340 | | | |vertex descriptor and value type | | | |
341 | | | |an integer type. | | | |
342 | +----------------+----------+---------------------------------+----------------------------------+ | |
343 | |``color_map`` | in/out |Model of |ReadWritePropertyMap|_ |an ``iterator_property_map`` | | |
344 | | | |with key type := ``graph``'s |created from a ``std::vector`` of | | |
345 | | | |vertex descriptor type. |``default_color_type`` of size | | |
346 | | | | |``num_vertices(graph)`` and using | | |
347 | | | | |``index_map`` for the index map. | | |
348 | +----------------+----------+---------------------------------+----------------------------------+ | |
349 | ||
350 | .. |IncidenceGraph| replace:: :concept:`Incidence Graph` | |
351 | .. |VertexListGraph| replace:: :concept:`Vertex List Graph` | |
352 | .. |DFSVisitor| replace:: :concept:`DFS Visitor` | |
353 | .. |ReadablePropertyMap| replace:: :concept:`Readable Property Map` | |
354 | .. |ReadWritePropertyMap| replace:: :concept:`Read/Write Property Map` | |
355 | ||
356 | .. _`IncidenceGraph`: ../../../graph/doc/IncidenceGraph.html | |
357 | .. _`VertexListGraph`: ../../../graph/doc/VertexListGraph.html | |
358 | .. _`DFSVisitor`: ../../../graph/doc/DFSVisitor.html | |
359 | .. _`ReadWritePropertyMap`: ../../../property_map/doc/ReadWritePropertyMap.html | |
360 | .. _`ReadablePropertyMap`: ../../../property_map/doc/ReadablePropertyMap.html | |
361 | ||
362 | Don't be intimidated by the information in the second and third | |
363 | columns above. For the purposes of this exercise, you don't need | |
364 | to understand them in detail. | |
365 | ||
366 | Defining the Keywords | |
367 | ===================== | |
368 | ||
369 | The point of this exercise is to make it possible to call | |
370 | ``depth_first_search`` with named arguments, leaving out any | |
371 | arguments for which the default is appropriate: | |
372 | ||
373 | .. parsed-literal:: | |
374 | ||
375 | graphs::depth_first_search(g, **color_map_=my_color_map**); | |
376 | ||
377 | .. @ignore() | |
378 | ||
379 | To make that syntax legal, there needs to be an object called | |
380 | “\ ``color_map_``\ ” whose assignment operator can accept a | |
381 | ``my_color_map`` argument. In this step we'll create one such | |
382 | **keyword object** for each parameter. Each keyword object will be | |
383 | identified by a unique **keyword tag type**. | |
384 | ||
385 | .. Revisit this | |
386 | ||
387 | We're going to define our interface in namespace ``graphs``. Since | |
388 | users need access to the keyword objects, but not the tag types, | |
389 | we'll define the keyword objects so they're accessible through | |
390 | ``graphs``, and we'll hide the tag types away in a nested | |
391 | namespace, ``graphs::tag``. The library provides a convenient | |
392 | macro for that purpose. | |
393 | ||
394 | We're going to define our interface in namespace ``graphs``. The | |
395 | library provides a convenient macro for defining keyword objects:: | |
396 | ||
397 | #include <boost/parameter/name.hpp> | |
398 | ||
399 | namespace graphs | |
400 | { | |
401 | BOOST_PARAMETER_NAME(graph) // Note: no semicolon | |
402 | BOOST_PARAMETER_NAME(visitor) | |
403 | BOOST_PARAMETER_NAME(root_vertex) | |
404 | BOOST_PARAMETER_NAME(index_map) | |
405 | BOOST_PARAMETER_NAME(color_map) | |
406 | } | |
407 | ||
408 | .. @test('compile') | |
409 | ||
410 | The declaration of the ``graph`` keyword you see here is | |
411 | equivalent to:: | |
412 | ||
413 | namespace graphs | |
414 | { | |
415 | namespace tag { struct graph; } // keyword tag type | |
416 | ||
417 | namespace // unnamed | |
418 | { | |
419 | // A reference to the keyword object | |
420 | boost::parameter::keyword<tag::graph>& _graph | |
421 | = boost::parameter::keyword<tag::graph>::get(); | |
422 | } | |
423 | } | |
424 | ||
425 | .. @example.prepend('#include <boost/parameter/keyword.hpp>') | |
426 | .. @test('compile') | |
427 | ||
428 | It defines a *keyword tag type* named ``tag::graph`` and a *keyword | |
429 | object* reference named ``_graph``. | |
430 | ||
431 | This “fancy dance” involving an unnamed namespace and references | |
432 | is all done to avoid violating the One Definition Rule (ODR) | |
433 | [#odr]_ when the named parameter interface is used by function | |
434 | templates that are instantiated in multiple translation | |
435 | units (MSVC6.x users see `this note`__). | |
436 | ||
437 | __ `Compiler Can't See References In Unnamed Namespace`_ | |
438 | ||
439 | Writing the Function | |
440 | ==================== | |
441 | ||
442 | Now that we have our keywords defined, the function template | |
443 | definition follows a simple pattern using the | |
444 | ``BOOST_PARAMETER_FUNCTION`` macro:: | |
445 | ||
446 | #include <boost/parameter/preprocessor.hpp> | |
447 | ||
448 | namespace graphs | |
449 | { | |
450 | BOOST_PARAMETER_FUNCTION( | |
451 | (void), // 1. parenthesized return type | |
452 | depth_first_search, // 2. name of the function template | |
453 | ||
454 | tag, // 3. namespace of tag types | |
455 | ||
456 | (required (graph, *) ) // 4. one required parameter, and | |
457 | ||
458 | (optional // four optional parameters, with defaults | |
459 | (visitor, *, boost::dfs_visitor<>()) | |
460 | (root_vertex, *, *vertices(graph).first) | |
461 | (index_map, *, get(boost::vertex_index,graph)) | |
462 | (in_out(color_map), *, | |
463 | default_color_map(num_vertices(graph), index_map) ) | |
464 | ) | |
465 | ) | |
466 | { | |
467 | // ... body of function goes here... | |
468 | // use graph, visitor, index_map, and color_map | |
469 | } | |
470 | } | |
471 | ||
472 | .. @example.prepend(''' | |
473 | #include <boost/parameter/name.hpp> | |
474 | ||
475 | BOOST_PARAMETER_NAME(graph) | |
476 | BOOST_PARAMETER_NAME(visitor) | |
477 | BOOST_PARAMETER_NAME(root_vertex) | |
478 | BOOST_PARAMETER_NAME(index_map) | |
479 | BOOST_PARAMETER_NAME(color_map) | |
480 | ||
481 | namespace boost { | |
482 | ||
483 | template <class T = int> | |
484 | struct dfs_visitor | |
485 | {}; | |
486 | ||
487 | int vertex_index = 0; | |
488 | ||
489 | }''') | |
490 | ||
491 | .. @test('compile') | |
492 | ||
493 | The arguments to ``BOOST_PARAMETER_FUNCTION`` are: | |
494 | ||
495 | 1. The return type of the resulting function template. Parentheses | |
496 | around the return type prevent any commas it might contain from | |
497 | confusing the preprocessor, and are always required. | |
498 | ||
499 | 2. The name of the resulting function template. | |
500 | ||
501 | 3. The name of a namespace where we can find tag types whose names | |
502 | match the function's parameter names. | |
503 | ||
504 | 4. The function signature. | |
505 | ||
506 | Function Signatures | |
507 | =================== | |
508 | ||
509 | Function signatures are described as one or two adjacent | |
510 | parenthesized terms (a Boost.Preprocessor_ sequence_) describing | |
511 | the function's parameters in the order in which they'd be expected | |
512 | if passed positionally. Any required parameters must come first, | |
513 | but the ``(required … )`` clause can be omitted when all the | |
514 | parameters are optional. | |
515 | ||
516 | .. _Boost.Preprocessor: ../../../preprocessor/index.html | |
517 | ||
518 | Required Parameters | |
519 | ------------------- | |
520 | ||
521 | .. compound:: | |
522 | ||
523 | Required parameters are given first—nested in a ``(required … )`` | |
524 | clause—as a series of two-element tuples describing each parameter | |
525 | name and any requirements on the argument type. In this case there | |
526 | is only a single required parameter, so there's just a single | |
527 | tuple: | |
528 | ||
529 | .. parsed-literal:: | |
530 | ||
531 | (required **(graph, \*)** ) | |
532 | ||
533 | Since ``depth_first_search`` doesn't require any particular type | |
534 | for its ``graph`` parameter, we use an asterix to indicate that | |
535 | any type is allowed. Required parameters must always precede any | |
536 | optional parameters in a signature, but if there are *no* | |
537 | required parameters, the ``(required … )`` clause can be omitted | |
538 | entirely. | |
539 | ||
540 | .. @example.prepend(''' | |
541 | #include <boost/parameter.hpp> | |
542 | ||
543 | BOOST_PARAMETER_NAME(graph) | |
544 | ||
545 | BOOST_PARAMETER_FUNCTION((void), f, tag, | |
546 | ''') | |
547 | ||
548 | .. @example.append(') {}') | |
549 | .. @test('compile') | |
550 | ||
551 | Optional Parameters | |
552 | ------------------- | |
553 | ||
554 | .. compound:: | |
555 | ||
556 | Optional parameters—nested in an ``(optional … )`` clause—are given | |
557 | as a series of adjacent *three*\ -element tuples describing the | |
558 | parameter name, any requirements on the argument type, *and* and an | |
559 | expression representing the parameter's default value: | |
560 | ||
561 | .. parsed-literal:: | |
562 | ||
563 | (optional **\ | |
564 | (visitor, \*, boost::dfs_visitor<>()) | |
565 | (root_vertex, \*, \*vertices(graph).first) | |
566 | (index_map, \*, get(boost::vertex_index,graph)) | |
567 | (in_out(color_map), \*, | |
568 | default_color_map(num_vertices(graph), index_map) )** | |
569 | ) | |
570 | ||
571 | .. @example.prepend(''' | |
572 | #include <boost/parameter.hpp> | |
573 | ||
574 | namespace boost | |
575 | { | |
576 | int vertex_index = 0; | |
577 | ||
578 | template <class T = int> | |
579 | struct dfs_visitor | |
580 | {}; | |
581 | } | |
582 | ||
583 | BOOST_PARAMETER_NAME(graph) | |
584 | BOOST_PARAMETER_NAME(visitor) | |
585 | BOOST_PARAMETER_NAME(root_vertex) | |
586 | BOOST_PARAMETER_NAME(index_map) | |
587 | BOOST_PARAMETER_NAME(color_map) | |
588 | ||
589 | BOOST_PARAMETER_FUNCTION((void), f, tag, | |
590 | (required (graph, *)) | |
591 | ''') | |
592 | ||
593 | .. @example.append(') {}') | |
594 | .. @test('compile') | |
595 | ||
596 | Handling “Out” Parameters | |
597 | ------------------------- | |
598 | ||
599 | .. compound:: | |
600 | ||
601 | Within the function body, a parameter name such as ``visitor`` is | |
602 | a *C++ reference*, bound either to an actual argument passed by | |
603 | the caller or to the result of evaluating a default expression. | |
604 | In most cases, parameter types are of the form ``T const&`` for | |
605 | some ``T``. Parameters whose values are expected to be modified, | |
606 | however, must be passed by reference to *non*\ -``const``. To | |
607 | indicate that ``color_map`` is both read and written, we wrap | |
608 | its name in ``in_out(…)``: | |
609 | ||
610 | .. parsed-literal:: | |
611 | ||
612 | (optional | |
613 | (visitor, \*, boost::dfs_visitor<>()) | |
614 | (root_vertex, \*, \*vertices(graph).first) | |
615 | (index_map, \*, get(boost::vertex_index,graph)) | |
616 | (**in_out(color_map)**, \*, | |
617 | default_color_map(num_vertices(graph), index_map) ) | |
618 | ) | |
619 | ||
620 | .. @example.prepend(''' | |
621 | #include <boost/parameter.hpp> | |
622 | ||
623 | namespace boost | |
624 | { | |
625 | int vertex_index = 0; | |
626 | ||
627 | template <class T = int> | |
628 | struct dfs_visitor | |
629 | {}; | |
630 | } | |
631 | ||
632 | BOOST_PARAMETER_NAME(graph) | |
633 | ||
634 | BOOST_PARAMETER_NAME(visitor) | |
635 | BOOST_PARAMETER_NAME(root_vertex) | |
636 | BOOST_PARAMETER_NAME(index_map) | |
637 | BOOST_PARAMETER_NAME(color_map) | |
638 | ||
639 | BOOST_PARAMETER_FUNCTION((void), f, tag, | |
640 | (required (graph, *)) | |
641 | ''') | |
642 | ||
643 | .. @example.append(') {}') | |
644 | .. @test('compile') | |
645 | ||
646 | If ``color_map`` were strictly going to be modified but not examined, | |
647 | we could have written ``out(color_map)``. There is no functional | |
648 | difference between ``out`` and ``in_out``; the library provides | |
649 | both so you can make your interfaces more self-documenting. | |
650 | ||
651 | Positional Arguments | |
652 | -------------------- | |
653 | ||
654 | When arguments are passed positionally (without the use of | |
655 | keywords), they will be mapped onto parameters in the order the | |
656 | parameters are given in the signature, so for example in this | |
657 | call :: | |
658 | ||
659 | graphs::depth_first_search(x, y); | |
660 | ||
661 | .. @ignore() | |
662 | ||
663 | ``x`` will always be interpreted as a graph and ``y`` will always | |
664 | be interpreted as a visitor. | |
665 | ||
666 | .. _sequence: http://boost-consulting.com/mplbook/preprocessor.html#sequences | |
667 | ||
668 | Default Expression Evaluation | |
669 | ----------------------------- | |
670 | ||
671 | .. compound:: | |
672 | ||
673 | Note that in our example, the value of the graph parameter is | |
674 | used in the default expressions for ``root_vertex``, | |
675 | ``index_map`` and ``color_map``. | |
676 | ||
677 | .. parsed-literal:: | |
678 | ||
679 | (required (**graph**, \*) ) | |
680 | (optional | |
681 | (visitor, \*, boost::dfs_visitor<>()) | |
682 | (root_vertex, \*, \*vertices(**graph**).first) | |
683 | (index_map, \*, get(boost::vertex_index,\ **graph**)) | |
684 | (in_out(color_map), \*, | |
685 | default_color_map(num_vertices(**graph**), index_map) ) | |
686 | ) | |
687 | ||
688 | .. @ignore() | |
689 | ||
690 | A default expression is evaluated in the context of all preceding | |
691 | parameters, so you can use any of their values by name. | |
692 | ||
693 | .. compound:: | |
694 | ||
695 | A default expression is never evaluated—or even instantiated—if | |
696 | an actual argument is passed for that parameter. We can actually | |
697 | demonstrate that with our code so far by replacing the body of | |
698 | ``depth_first_search`` with something that prints the arguments: | |
699 | ||
700 | .. parsed-literal:: | |
701 | ||
702 | #include <boost/graph/depth_first_search.hpp> // for dfs_visitor | |
703 | ||
704 | BOOST_PARAMETER_FUNCTION( | |
705 | (void), depth_first_search, tag | |
706 | *…signature goes here…* | |
707 | ) | |
708 | { | |
709 | std::cout << "graph=" << graph << std::endl; | |
710 | std::cout << "visitor=" << visitor << std::endl; | |
711 | std::cout << "root_vertex=" << root_vertex << std::endl; | |
712 | std::cout << "index_map=" << index_map << std::endl; | |
713 | std::cout << "color_map=" << color_map << std::endl; | |
714 | } | |
715 | ||
716 | int main() | |
717 | { | |
718 | depth_first_search(1, 2, 3, 4, 5); | |
719 | ||
720 | depth_first_search( | |
721 | "1", '2', _color_map = '5', | |
722 | _index_map = "4", _root_vertex = "3"); | |
723 | } | |
724 | ||
725 | Despite the fact that default expressions such as | |
726 | ``vertices(graph).first`` are ill-formed for the given ``graph`` | |
727 | arguments, both calls will compile, and each one will print | |
728 | exactly the same thing. | |
729 | ||
730 | .. @example.prepend(''' | |
731 | #include <boost/parameter.hpp> | |
732 | #include <iostream> | |
733 | ||
734 | BOOST_PARAMETER_NAME(graph) | |
735 | BOOST_PARAMETER_NAME(visitor) | |
736 | BOOST_PARAMETER_NAME(root_vertex) | |
737 | BOOST_PARAMETER_NAME(index_map) | |
738 | BOOST_PARAMETER_NAME(color_map)''') | |
739 | ||
740 | .. @example.replace_emphasis(''' | |
741 | , (required | |
742 | (graph, *) | |
743 | (visitor, *) | |
744 | (root_vertex, *) | |
745 | (index_map, *) | |
746 | (color_map, *) | |
747 | ) | |
748 | ''') | |
749 | .. @test('compile') | |
750 | ||
751 | Signature Matching and Overloading | |
752 | ---------------------------------- | |
753 | ||
754 | In fact, the function signature is so general that any call to | |
755 | ``depth_first_search`` with fewer than five arguments will match | |
756 | our function, provided we pass *something* for the required | |
757 | ``graph`` parameter. That might not seem to be a problem at first; | |
758 | after all, if the arguments don't match the requirements imposed by | |
759 | the implementation of ``depth_first_search``, a compilation error | |
760 | will occur later, when its body is instantiated. | |
761 | ||
762 | There are at least three problems with very general function | |
763 | signatures. | |
764 | ||
765 | 1. By the time our ``depth_first_search`` is instantiated, it has | |
766 | been selected as the best matching overload. Some other | |
767 | ``depth_first_search`` overload might've worked had it been | |
768 | chosen instead. By the time we see a compilation error, there's | |
769 | no chance to change that decision. | |
770 | ||
771 | 2. Even if there are no overloads, error messages generated at | |
772 | instantiation time usually expose users to confusing | |
773 | implementation details. For example, users might see references | |
774 | to names generated by ``BOOST_PARAMETER_FUNCTION`` such as | |
775 | ``graphs::detail::depth_first_search_with_named_params`` (or | |
776 | worse—think of the kinds of errors you get from your STL | |
777 | implementation when you make a mistake). [#ConceptCpp]_ | |
778 | ||
779 | 3. The problems with exposing such permissive function template | |
780 | signatures have been the subject of much discussion, especially | |
781 | in the presence of `unqualified calls`__. If all we want is to | |
782 | avoid unintentional argument-dependent lookup (ADL), we can | |
783 | isolate ``depth_first_search`` in a namespace containing no | |
784 | types [#using]_, but suppose we *want* it to found via ADL? | |
785 | ||
786 | __ http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#225 | |
787 | ||
788 | It's usually a good idea to prevent functions from being considered | |
789 | for overload resolution when the passed argument types aren't | |
790 | appropriate. The library already does this when the required | |
791 | ``graph`` parameter is not supplied, but we're not likely to see a | |
792 | depth first search that doesn't take a graph to operate on. | |
793 | Suppose, instead, that we found a different depth first search | |
794 | algorithm that could work on graphs that don't model | |
795 | |IncidenceGraph|_? If we just added a simple overload, | |
796 | it would be ambiguous:: | |
797 | ||
798 | // new overload | |
799 | BOOST_PARAMETER_FUNCTION( | |
800 | (void), depth_first_search, (tag), (required (graph,*))( … )) | |
801 | { | |
802 | // new algorithm implementation | |
803 | } | |
804 | ||
805 | … | |
806 | ||
807 | // ambiguous! | |
808 | depth_first_search(boost::adjacency_list<>(), 2, "hello"); | |
809 | ||
810 | .. @ignore() | |
811 | ||
812 | Adding Type Requirements | |
813 | ........................ | |
814 | ||
815 | We really don't want the compiler to consider the original version | |
816 | of ``depth_first_search`` because the ``root_vertex`` argument, | |
817 | ``"hello"``, doesn't meet the requirement__ that it match the | |
818 | ``graph`` parameter's vertex descriptor type. Instead, this call | |
819 | should just invoke our new overload. To take the original | |
820 | ``depth_first_search`` overload out of contention, we need to tell | |
821 | the library about this requirement by replacing the ``*`` element | |
822 | of the signature with the required type, in parentheses: | |
823 | ||
824 | __ `parameter table`_ | |
825 | ||
826 | .. parsed-literal:: | |
827 | ||
828 | (root_vertex, | |
829 | **(typename boost::graph_traits<graph_type>::vertex_descriptor)**, | |
830 | \*vertices(graph).first) | |
831 | ||
832 | .. @ignore() | |
833 | ||
834 | Now the original ``depth_first_search`` will only be called when | |
835 | the ``root_vertex`` argument can be converted to the graph's vertex | |
836 | descriptor type, and our example that *was* ambiguous will smoothly | |
837 | call the new overload. | |
838 | ||
839 | .. Note:: The *type* of the ``graph`` argument is available in the | |
840 | signature—and in the function body—as ``graph_type``. In | |
841 | general, to access the type of any parameter *foo*, write *foo*\ | |
842 | ``_type``. | |
843 | ||
844 | ||
845 | Predicate Requirements | |
846 | ...................... | |
847 | ||
848 | The requirements on other arguments are a bit more interesting than | |
849 | those on ``root_vertex``; they can't be described in terms of simple | |
850 | type matching. Instead, they must be described in terms of `MPL | |
851 | Metafunctions`__. There's no space to give a complete description | |
852 | of metafunctions or of graph library details here, but we'll show | |
853 | you the complete signature with maximal checking, just to give you | |
854 | a feel for how it's done. Each predicate metafunction is enclosed | |
855 | in parentheses *and preceded by an asterix*, as follows: | |
856 | ||
857 | .. parsed-literal:: | |
858 | ||
859 | // We first need to define a few metafunction that we use in the | |
860 | // predicates below. | |
861 | ||
862 | template <class G> | |
863 | struct traversal_category | |
864 | { | |
865 | typedef typename boost::graph_traits<G>::traversal_category type; | |
866 | }; | |
867 | ||
868 | template <class G> | |
869 | struct vertex_descriptor | |
870 | { | |
871 | typedef typename boost::graph_traits<G>::vertex_descriptor type; | |
872 | }; | |
873 | ||
874 | template <class G> | |
875 | struct value_type | |
876 | { | |
877 | typedef typename boost::property_traits<G>::value_type type; | |
878 | }; | |
879 | ||
880 | template <class G> | |
881 | struct key_type | |
882 | { | |
883 | typedef typename boost::property_traits<G>::key_type type; | |
884 | }; | |
885 | ||
886 | template<class Size, class IndexMap> | |
887 | boost::iterator_property_map< | |
888 | boost::default_color_type\*, IndexMap | |
889 | , boost::default_color_type, boost::default_color_type& | |
890 | > | |
891 | default_color_map(Size num_vertices, IndexMap const& index_map) | |
892 | { | |
893 | std::vector<boost::default_color_type> colors(num_vertices); | |
894 | return &colors[0]; | |
895 | } | |
896 | ||
897 | BOOST_PARAMETER_FUNCTION( | |
898 | (void), depth_first_search, graphs | |
899 | ||
900 | , (required | |
901 | (graph | |
902 | , **\ \*(boost::mpl::and_< | |
903 | boost::is_convertible< | |
904 | traversal_category<_>, boost::incidence_graph_tag | |
905 | > | |
906 | , boost::is_convertible< | |
907 | traversal_category<_>, boost::vertex_list_graph_tag | |
908 | > | |
909 | >)** )) | |
910 | ||
911 | (optional | |
912 | (visitor, \*, boost::dfs_visitor<>()) // not checkable | |
913 | ||
914 | (root_vertex | |
915 | , (vertex_descriptor<graphs::graph::_>) | |
916 | , \*vertices(graph).first) | |
917 | ||
918 | (index_map | |
919 | , **\ \*(boost::mpl::and_< | |
920 | boost::is_integral<value_type<_> > | |
921 | , boost::is_same< | |
922 | vertex_descriptor<graphs::graph::_>, key_type<_> | |
923 | > | |
924 | >)** | |
925 | , get(boost::vertex_index,graph)) | |
926 | ||
927 | (in_out(color_map) | |
928 | , **\ \*(boost::is_same< | |
929 | vertex_descriptor<graphs::graph::_>, key_type<_> | |
930 | >)** | |
931 | , default_color_map(num_vertices(graph), index_map) ) | |
932 | ) | |
933 | ) | |
934 | ||
935 | .. @example.prepend(''' | |
936 | #include <boost/parameter.hpp> | |
937 | #include <boost/graph/adjacency_list.hpp> | |
938 | #include <boost/graph/depth_first_search.hpp> | |
939 | ||
940 | BOOST_PARAMETER_NAME((_graph, graphs) graph) | |
941 | BOOST_PARAMETER_NAME((_visitor, graphs) visitor) | |
942 | BOOST_PARAMETER_NAME((_root_vertex, graphs) root_vertex) | |
943 | BOOST_PARAMETER_NAME((_index_map, graphs) index_map) | |
944 | BOOST_PARAMETER_NAME((_color_map, graphs) color_map) | |
945 | ||
946 | using boost::mpl::_; | |
947 | ''') | |
948 | ||
949 | .. @example.append(''' | |
950 | {} | |
951 | ||
952 | int main() | |
953 | { | |
954 | typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> G; | |
955 | ||
956 | enum {u, v, w, x, y, z, N}; | |
957 | typedef std::pair<int, int> E; | |
958 | E edges[] = {E(u, v), E(u, x), E(x, v), E(y, x), E(v, y), E(w, y), | |
959 | E(w,z), E(z, z)}; | |
960 | G g(edges, edges + sizeof(edges) / sizeof(E), N); | |
961 | ||
962 | depth_first_search(g); | |
963 | depth_first_search(g, _root_vertex = (int)x); | |
964 | } | |
965 | ''') | |
966 | ||
967 | .. @test('compile') | |
968 | ||
969 | Note the use of the nested `tag::_`. This is a shortcut for:: | |
970 | ||
971 | value_type<boost::mpl::_2, tag> | |
972 | ||
973 | .. @ignore() | |
974 | ||
975 | Intended to be used to access preceding arguments types in the | |
976 | predicates. | |
977 | ||
978 | __ ../../../mpl/doc/refmanual/metafunction.html | |
979 | ||
980 | We acknowledge that this signature is pretty hairy looking. | |
981 | Fortunately, it usually isn't necessary to so completely encode the | |
982 | type requirements on arguments to generic functions. However, it | |
983 | is usally worth the effort to do so: your code will be more | |
984 | self-documenting and will often provide a better user experience. | |
985 | You'll also have an easier transition to an upcoming C++ standard | |
986 | with `language support for concepts`__. | |
987 | ||
988 | __ `ConceptC++`_ | |
989 | ||
990 | Deduced Parameters | |
991 | ------------------ | |
992 | ||
993 | To illustrate deduced parameter support we'll have to leave behind | |
994 | our example from the Graph library. Instead, consider the example | |
995 | of the |def|_ function from Boost.Python_. Its signature is | |
996 | roughly as follows:: | |
997 | ||
998 | template < | |
999 | class Function, Class KeywordExpression, class CallPolicies | |
1000 | > | |
1001 | void def( | |
1002 | // Required parameters | |
1003 | char const* name, Function func | |
1004 | ||
1005 | // Optional, deduced parameters | |
1006 | , char const* docstring = "" | |
1007 | , KeywordExpression keywords = no_keywords() | |
1008 | , CallPolicies policies = default_call_policies() | |
1009 | ); | |
1010 | ||
1011 | .. @ignore() | |
1012 | ||
1013 | Try not to be too distracted by the use of the term “keywords” in | |
1014 | this example: although it means something analogous in Boost.Python | |
1015 | to what it means in the Parameter library, for the purposes of this | |
1016 | exercise you can think of it as being completely different. | |
1017 | ||
1018 | When calling ``def``, only two arguments are required. The | |
1019 | association between any additional arguments and their parameters | |
1020 | can be determined by the types of the arguments actually passed, so | |
1021 | the caller is neither required to remember argument positions or | |
1022 | explicitly specify parameter names for those arguments. To | |
1023 | generate this interface using ``BOOST_PARAMETER_FUNCTION``, we need | |
1024 | only enclose the deduced parameters in a ``(deduced …)`` clause, as | |
1025 | follows: | |
1026 | ||
1027 | .. parsed-literal:: | |
1028 | ||
1029 | namespace mpl = boost::mpl; | |
1030 | ||
1031 | BOOST_PARAMETER_FUNCTION( | |
1032 | (void), def, tag, | |
1033 | ||
1034 | (required (name,(char const\*)) (func,\*) ) // nondeduced | |
1035 | ||
1036 | **(deduced** | |
1037 | (optional | |
1038 | (docstring, (char const\*), "") | |
1039 | ||
1040 | (keywords | |
1041 | , \*(is_keyword_expression<mpl::_>) // see [#is_keyword_expression]_ | |
1042 | , no_keywords()) | |
1043 | ||
1044 | (policies | |
1045 | , \*(mpl::not_< | |
1046 | mpl::or_< | |
1047 | boost::is_convertible<mpl::_, char const\*> | |
1048 | , is_keyword_expression<mpl::_> // see [#is_keyword_expression]_ | |
1049 | > | |
1050 | >) | |
1051 | , default_call_policies() | |
1052 | ) | |
1053 | ) | |
1054 | **)** | |
1055 | ) | |
1056 | { | |
1057 | *…* | |
1058 | } | |
1059 | ||
1060 | .. @example.replace_emphasis('') | |
1061 | ||
1062 | .. @example.prepend(''' | |
1063 | #include <boost/parameter.hpp> | |
1064 | ||
1065 | BOOST_PARAMETER_NAME(name) | |
1066 | BOOST_PARAMETER_NAME(func) | |
1067 | BOOST_PARAMETER_NAME(docstring) | |
1068 | BOOST_PARAMETER_NAME(keywords) | |
1069 | BOOST_PARAMETER_NAME(policies) | |
1070 | ||
1071 | struct default_call_policies | |
1072 | {}; | |
1073 | ||
1074 | struct no_keywords | |
1075 | {}; | |
1076 | ||
1077 | struct keywords | |
1078 | {}; | |
1079 | ||
1080 | template <class T> | |
1081 | struct is_keyword_expression | |
1082 | : boost::mpl::false_ | |
1083 | {}; | |
1084 | ||
1085 | template <> | |
1086 | struct is_keyword_expression<keywords> | |
1087 | : boost::mpl::true_ | |
1088 | {}; | |
1089 | ||
1090 | default_call_policies some_policies; | |
1091 | ||
1092 | void f() | |
1093 | {} | |
1094 | ||
1095 | ''') | |
1096 | ||
1097 | .. Admonition:: Syntax Note | |
1098 | ||
1099 | A ``(deduced …)`` clause always contains a ``(required …)`` | |
1100 | and/or an ``(optional …)`` subclause, and must follow any | |
1101 | ``(required …)`` or ``(optional …)`` clauses indicating | |
1102 | nondeduced parameters at the outer level. | |
1103 | ||
1104 | With the declaration above, the following two calls are equivalent: | |
1105 | ||
1106 | .. parsed-literal:: | |
1107 | ||
1108 | def("f", &f, **some_policies**, **"Documentation for f"**); | |
1109 | def("f", &f, **"Documentation for f"**, **some_policies**); | |
1110 | ||
1111 | .. @example.prepend(''' | |
1112 | int main() | |
1113 | {''') | |
1114 | ||
1115 | If the user wants to pass a ``policies`` argument that was also, | |
1116 | for some reason, convertible to ``char const*``, she can always | |
1117 | specify the parameter name explicitly, as follows: | |
1118 | ||
1119 | .. parsed-literal:: | |
1120 | ||
1121 | def( | |
1122 | "f", &f | |
1123 | , **_policies = some_policies**, "Documentation for f"); | |
1124 | ||
1125 | .. @example.append('}') | |
1126 | .. @test('compile', howmany='all') | |
1127 | ||
1128 | .. _Boost.Python: ../../../python/doc/index.html | |
1129 | .. |def| replace:: ``def`` | |
1130 | .. _def: ../../../python/doc/v2/def.html | |
1131 | ||
1132 | ---------------------------------- | |
1133 | Parameter-Enabled Member Functions | |
1134 | ---------------------------------- | |
1135 | ||
1136 | ||
1137 | The ``BOOST_PARAMETER_MEMBER_FUNCTION`` and | |
1138 | ``BOOST_PARAMETER_CONST_MEMBER_FUNCTION`` macros accept exactly the | |
1139 | same arguments as ``BOOST_PARAMETER_FUNCTION``, but are designed to | |
1140 | be used within the body of a class:: | |
1141 | ||
1142 | BOOST_PARAMETER_NAME(arg1) | |
1143 | BOOST_PARAMETER_NAME(arg2) | |
1144 | ||
1145 | struct callable2 | |
1146 | { | |
1147 | BOOST_PARAMETER_CONST_MEMBER_FUNCTION( | |
1148 | (void), call, tag, (required (arg1,(int))(arg2,(int)))) | |
1149 | { | |
1150 | std::cout << arg1 << ", " << arg2 << std::endl; | |
1151 | } | |
1152 | }; | |
1153 | ||
1154 | .. @example.prepend(''' | |
1155 | #include <boost/parameter.hpp> | |
1156 | #include <iostream> | |
1157 | using namespace boost::parameter; | |
1158 | ''') | |
1159 | ||
1160 | .. @test('compile') | |
1161 | ||
1162 | These macros don't directly allow a function's interface to be | |
1163 | separated from its implementation, but you can always forward | |
1164 | arguments on to a separate implementation function:: | |
1165 | ||
1166 | struct callable2 | |
1167 | { | |
1168 | BOOST_PARAMETER_CONST_MEMBER_FUNCTION( | |
1169 | (void), call, tag, (required (arg1,(int))(arg2,(int)))) | |
1170 | { | |
1171 | call_impl(arg1,arg2); | |
1172 | } | |
1173 | private: | |
1174 | void call_impl(int, int); // implemented elsewhere. | |
1175 | }; | |
1176 | ||
1177 | .. @example.prepend(''' | |
1178 | #include <boost/parameter.hpp> | |
1179 | ||
1180 | BOOST_PARAMETER_NAME(arg1) | |
1181 | BOOST_PARAMETER_NAME(arg2) | |
1182 | using namespace boost::parameter; | |
1183 | ''') | |
1184 | ||
1185 | .. @test('compile') | |
1186 | ||
1187 | Static Member Functions | |
1188 | ======================= | |
1189 | ||
1190 | To expose a static member function, simply insert the keyword | |
1191 | “``static``” before the function name: | |
1192 | ||
1193 | .. parsed-literal:: | |
1194 | ||
1195 | BOOST_PARAMETER_NAME(arg1) | |
1196 | ||
1197 | struct somebody | |
1198 | { | |
1199 | BOOST_PARAMETER_MEMBER_FUNCTION( | |
1200 | (void), **static** f, tag, (optional (arg1,(int),0))) | |
1201 | { | |
1202 | std::cout << arg1 << std::endl; | |
1203 | } | |
1204 | }; | |
1205 | ||
1206 | .. @example.prepend(''' | |
1207 | #include <boost/parameter.hpp> | |
1208 | #include <iostream> | |
1209 | using namespace boost::parameter; | |
1210 | ''') | |
1211 | ||
1212 | .. @test('compile') | |
1213 | ||
1214 | ||
1215 | ------------------------------ | |
1216 | Parameter-Enabled Constructors | |
1217 | ------------------------------ | |
1218 | ||
1219 | The lack of a “delegating constructor” | |
1220 | feature in C++ | |
1221 | (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf) | |
1222 | limits somewhat the quality of interface this library can provide | |
1223 | for defining parameter-enabled constructors. The usual workaround | |
1224 | for a lack of constructor delegation applies: one must factor the | |
1225 | common logic into a base class. | |
1226 | ||
1227 | Let's build a parameter-enabled constructor that simply prints its | |
1228 | arguments. The first step is to write a base class whose | |
1229 | constructor accepts a single argument known as an |ArgumentPack|_: | |
1230 | a bundle of references to the actual arguments, tagged with their | |
1231 | keywords. The values of the actual arguments are extracted from | |
1232 | the |ArgumentPack| by *indexing* it with keyword objects:: | |
1233 | ||
1234 | BOOST_PARAMETER_NAME(name) | |
1235 | BOOST_PARAMETER_NAME(index) | |
1236 | ||
1237 | struct myclass_impl | |
1238 | { | |
1239 | template <class ArgumentPack> | |
1240 | myclass_impl(ArgumentPack const& args) | |
1241 | { | |
1242 | std::cout << "name = " << args[_name] | |
1243 | << "; index = " << args[_index | 42] | |
1244 | << std::endl; | |
1245 | } | |
1246 | }; | |
1247 | ||
1248 | .. @example.prepend(''' | |
1249 | #include <boost/parameter.hpp> | |
1250 | #include <iostream>''') | |
1251 | ||
1252 | Note that the bitwise or (“\ ``|``\ ”) operator has a special | |
1253 | meaning when applied to keyword objects that are passed to an | |
1254 | |ArgumentPack|\ 's indexing operator: it is used to indicate a | |
1255 | default value. In this case if there is no ``index`` parameter in | |
1256 | the |ArgumentPack|, ``42`` will be used instead. | |
1257 | ||
1258 | Now we are ready to write the parameter-enabled constructor | |
1259 | interface:: | |
1260 | ||
1261 | struct myclass : myclass_impl | |
1262 | { | |
1263 | BOOST_PARAMETER_CONSTRUCTOR( | |
1264 | myclass, (myclass_impl), tag | |
1265 | , (required (name,*)) (optional (index,*))) // no semicolon | |
1266 | }; | |
1267 | ||
1268 | Since we have supplied a default value for ``index`` but not for | |
1269 | ``name``, only ``name`` is required. We can exercise our new | |
1270 | interface as follows:: | |
1271 | ||
1272 | myclass x("bob", 3); // positional | |
1273 | myclass y(_index = 12, _name = "sally"); // named | |
1274 | myclass z("june"); // positional/defaulted | |
1275 | ||
1276 | .. @example.wrap('int main() {', '}') | |
1277 | .. @test('run', howmany='all') | |
1278 | ||
1279 | For more on |ArgumentPack| manipulation, see the `Advanced Topics`_ | |
1280 | section. | |
1281 | ||
1282 | --------------------------------- | |
1283 | Parameter-Enabled Class Templates | |
1284 | --------------------------------- | |
1285 | ||
1286 | In this section we'll use Boost.Parameter to build Boost.Python_\ | |
1287 | 's `class_`_ template, whose “signature” is: | |
1288 | ||
1289 | .. parsed-literal:: | |
1290 | ||
1291 | template class< | |
1292 | ValueType, BaseList = bases<> | |
1293 | , HeldType = ValueType, Copyable = void | |
1294 | > | |
1295 | class class\_; | |
1296 | ||
1297 | .. @ignore() | |
1298 | ||
1299 | Only the first argument, ``ValueType``, is required. | |
1300 | ||
1301 | .. _class_: http://www.boost.org/libs/python/doc/v2/class.html#class_-spec | |
1302 | ||
1303 | Named Template Parameters | |
1304 | ========================= | |
1305 | ||
1306 | First, we'll build an interface that allows users to pass arguments | |
1307 | positionally or by name: | |
1308 | ||
1309 | .. parsed-literal:: | |
1310 | ||
1311 | struct B { virtual ~B() = 0; }; | |
1312 | struct D : B { ~D(); }; | |
1313 | ||
1314 | class_< | |
1315 | **class_type<B>**, **copyable<boost::noncopyable>** | |
1316 | > …; | |
1317 | ||
1318 | class_< | |
1319 | **D**, **held_type<std::auto_ptr<D> >**, **base_list<bases<B> >** | |
1320 | > …; | |
1321 | ||
1322 | .. @ignore() | |
1323 | ||
1324 | Template Keywords | |
1325 | ----------------- | |
1326 | ||
1327 | The first step is to define keywords for each template parameter:: | |
1328 | ||
1329 | namespace boost { namespace python { | |
1330 | ||
1331 | BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type) | |
1332 | BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list) | |
1333 | BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type) | |
1334 | BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable) | |
1335 | ||
1336 | }} | |
1337 | ||
1338 | .. @example.prepend('#include <boost/parameter.hpp>') | |
1339 | .. @test('compile') | |
1340 | ||
1341 | The declaration of the ``class_type`` keyword you see here is | |
1342 | equivalent to:: | |
1343 | ||
1344 | namespace boost { namespace python { | |
1345 | ||
1346 | namespace tag { struct class_type; } // keyword tag type | |
1347 | template <class T> | |
1348 | struct class_type | |
1349 | : parameter::template_keyword<tag::class_type,T> | |
1350 | {}; | |
1351 | ||
1352 | }} | |
1353 | ||
1354 | .. @example.prepend('#include <boost/parameter.hpp>') | |
1355 | .. @test('compile') | |
1356 | ||
1357 | It defines a keyword tag type named ``tag::class_type`` and a | |
1358 | *parameter passing template* named ``class_type``. | |
1359 | ||
1360 | Class Template Skeleton | |
1361 | ----------------------- | |
1362 | ||
1363 | The next step is to define the skeleton of our class template, | |
1364 | which has three optional parameters. Because the user may pass | |
1365 | arguments in any order, we don't know the actual identities of | |
1366 | these parameters, so it would be premature to use descriptive names | |
1367 | or write out the actual default values for any of them. Instead, | |
1368 | we'll give them generic names and use the special type | |
1369 | ``boost::parameter::void_`` as a default: | |
1370 | ||
1371 | .. parsed-literal:: | |
1372 | ||
1373 | namespace boost { namespace python { | |
1374 | ||
1375 | template < | |
1376 | class A0 | |
1377 | , class A1 = parameter::void\_ | |
1378 | , class A2 = parameter::void\_ | |
1379 | , class A3 = parameter::void\_ | |
1380 | > | |
1381 | struct class\_ | |
1382 | { | |
1383 | *…* | |
1384 | }; | |
1385 | ||
1386 | }} | |
1387 | ||
1388 | .. @example.prepend('#include <boost/parameter.hpp>') | |
1389 | .. @example.replace_emphasis('') | |
1390 | .. @test('compile') | |
1391 | ||
1392 | Class Template Signatures | |
1393 | ------------------------- | |
1394 | ||
1395 | Next, we need to build a type, known as a |ParameterSpec|_, | |
1396 | describing the “signature” of ``boost::python::class_``. A | |
1397 | |ParameterSpec|_ enumerates the required and optional parameters in | |
1398 | their positional order, along with any type requirements (note that | |
1399 | it does *not* specify defaults -- those will be dealt with | |
1400 | separately):: | |
1401 | ||
1402 | namespace boost { namespace python { | |
1403 | ||
1404 | using boost::mpl::_; | |
1405 | ||
1406 | typedef parameter::parameters< | |
1407 | required<tag::class_type, boost::is_class<_> > | |
1408 | , parameter::optional<tag::base_list, mpl::is_sequence<_> > | |
1409 | , parameter::optional<tag::held_type> | |
1410 | , parameter::optional<tag::copyable> | |
1411 | > class_signature; | |
1412 | ||
1413 | }} | |
1414 | ||
1415 | .. @example.prepend(''' | |
1416 | #include <boost/parameter.hpp> | |
1417 | #include <boost/mpl/is_sequence.hpp> | |
1418 | #include <boost/noncopyable.hpp> | |
1419 | #include <boost/type_traits/is_class.hpp> | |
1420 | #include <memory> | |
1421 | ||
1422 | using namespace boost::parameter; | |
1423 | ||
1424 | namespace boost { namespace python { | |
1425 | ||
1426 | BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type) | |
1427 | BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list) | |
1428 | BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type) | |
1429 | BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable) | |
1430 | ||
1431 | template <class B = int> | |
1432 | struct bases | |
1433 | {}; | |
1434 | ||
1435 | }}''') | |
1436 | ||
1437 | .. |ParameterSpec| replace:: :concept:`ParameterSpec` | |
1438 | ||
1439 | .. _ParameterSpec: reference.html#parameterspec | |
1440 | ||
1441 | .. _binding_intro: | |
1442 | ||
1443 | Argument Packs and Parameter Extraction | |
1444 | --------------------------------------- | |
1445 | ||
1446 | Next, within the body of ``class_`` , we use the |ParameterSpec|\ 's | |
1447 | nested ``::bind< … >`` template to bundle the actual arguments into an | |
1448 | |ArgumentPack|_ type, and then use the library's ``value_type< … >`` | |
1449 | metafunction to extract “logical parameters”. ``value_type< … >`` is | |
1450 | a lot like ``binding< … >``, but no reference is added to the actual | |
1451 | argument type. Note that defaults are specified by passing it an | |
1452 | optional third argument:: | |
1453 | ||
1454 | namespace boost { namespace python { | |
1455 | ||
1456 | template < | |
1457 | class A0 | |
1458 | , class A1 = parameter::void_ | |
1459 | , class A2 = parameter::void_ | |
1460 | , class A3 = parameter::void_ | |
1461 | > | |
1462 | struct class_ | |
1463 | { | |
1464 | // Create ArgumentPack | |
1465 | typedef typename | |
1466 | class_signature::bind<A0,A1,A2,A3>::type | |
1467 | args; | |
1468 | ||
1469 | // Extract first logical parameter. | |
1470 | typedef typename parameter::value_type< | |
1471 | args, tag::class_type>::type class_type; | |
1472 | ||
1473 | typedef typename parameter::value_type< | |
1474 | args, tag::base_list, bases<> >::type base_list; | |
1475 | ||
1476 | typedef typename parameter::value_type< | |
1477 | args, tag::held_type, class_type>::type held_type; | |
1478 | ||
1479 | typedef typename parameter::value_type< | |
1480 | args, tag::copyable, void>::type copyable; | |
1481 | }; | |
1482 | ||
1483 | }} | |
1484 | ||
1485 | .. |ArgumentPack| replace:: :concept:`ArgumentPack` | |
1486 | .. _ArgumentPack: reference.html#argumentpack | |
1487 | ||
1488 | Exercising the Code So Far | |
1489 | ========================== | |
1490 | ||
1491 | .. compound:: | |
1492 | ||
1493 | Revisiting our original examples, :: | |
1494 | ||
1495 | typedef boost::python::class_< | |
1496 | class_type<B>, copyable<boost::noncopyable> | |
1497 | > c1; | |
1498 | ||
1499 | typedef boost::python::class_< | |
1500 | D, held_type<std::auto_ptr<D> >, base_list<bases<B> > | |
1501 | > c2; | |
1502 | ||
1503 | .. @example.prepend(''' | |
1504 | using boost::python::class_type; | |
1505 | using boost::python::copyable; | |
1506 | using boost::python::held_type; | |
1507 | using boost::python::base_list; | |
1508 | using boost::python::bases; | |
1509 | ||
1510 | struct B {}; | |
1511 | struct D {};''') | |
1512 | ||
1513 | we can now examine the intended parameters:: | |
1514 | ||
1515 | BOOST_MPL_ASSERT((boost::is_same<c1::class_type, B>)); | |
1516 | BOOST_MPL_ASSERT((boost::is_same<c1::base_list, bases<> >)); | |
1517 | BOOST_MPL_ASSERT((boost::is_same<c1::held_type, B>)); | |
1518 | BOOST_MPL_ASSERT(( | |
1519 | boost::is_same<c1::copyable, boost::noncopyable> | |
1520 | )); | |
1521 | ||
1522 | BOOST_MPL_ASSERT((boost::is_same<c2::class_type, D>)); | |
1523 | BOOST_MPL_ASSERT((boost::is_same<c2::base_list, bases<B> >)); | |
1524 | BOOST_MPL_ASSERT(( | |
1525 | boost::is_same<c2::held_type, std::auto_ptr<D> > | |
1526 | )); | |
1527 | BOOST_MPL_ASSERT((boost::is_same<c2::copyable, void>)); | |
1528 | ||
1529 | .. @test('compile', howmany='all') | |
1530 | ||
1531 | Deduced Template Parameters | |
1532 | =========================== | |
1533 | ||
1534 | To apply a deduced parameter interface here, we need only make the | |
1535 | type requirements a bit tighter so the ``held_type`` and | |
1536 | ``copyable`` parameters can be crisply distinguished from the | |
1537 | others. Boost.Python_ does this by requiring that ``base_list`` be | |
1538 | a specialization of its ``bases< … >`` template (as opposed to | |
1539 | being any old MPL sequence) and by requiring that ``copyable``, if | |
1540 | explicitly supplied, be ``boost::noncopyable``. One easy way of | |
1541 | identifying specializations of ``bases< … >`` is to derive them all | |
1542 | from the same class, as an implementation detail: | |
1543 | ||
1544 | .. parsed-literal:: | |
1545 | ||
1546 | namespace boost { namespace python { | |
1547 | ||
1548 | namespace detail { struct bases_base {}; } | |
1549 | ||
1550 | template <class A0 = void, class A1 = void, class A2 = void *…* > | |
1551 | struct bases **: detail::bases_base** | |
1552 | {}; | |
1553 | ||
1554 | }} | |
1555 | ||
1556 | .. @example.replace_emphasis('') | |
1557 | .. @example.prepend(''' | |
1558 | #include <boost/parameter.hpp> | |
1559 | #include <boost/mpl/is_sequence.hpp> | |
1560 | #include <boost/noncopyable.hpp> | |
1561 | #include <memory> | |
1562 | ||
1563 | using namespace boost::parameter; | |
1564 | using boost::mpl::_; | |
1565 | ||
1566 | namespace boost { namespace python { | |
1567 | ||
1568 | BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type) | |
1569 | BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list) | |
1570 | BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type) | |
1571 | BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable) | |
1572 | ||
1573 | }}''') | |
1574 | ||
1575 | Now we can rewrite our signature to make all three optional | |
1576 | parameters deducible:: | |
1577 | ||
1578 | typedef parameter::parameters< | |
1579 | required<tag::class_type, is_class<_> > | |
1580 | ||
1581 | , parameter::optional< | |
1582 | deduced<tag::base_list> | |
1583 | , is_base_and_derived<detail::bases_base,_> | |
1584 | > | |
1585 | ||
1586 | , parameter::optional< | |
1587 | deduced<tag::held_type> | |
1588 | , mpl::not_< | |
1589 | mpl::or_< | |
1590 | is_base_and_derived<detail::bases_base,_> | |
1591 | , is_same<noncopyable,_> | |
1592 | > | |
1593 | > | |
1594 | > | |
1595 | ||
1596 | , parameter::optional<deduced<tag::copyable>, is_same<noncopyable,_> > | |
1597 | ||
1598 | > class_signature; | |
1599 | ||
1600 | .. @example.prepend(''' | |
1601 | #include <boost/type_traits/is_class.hpp> | |
1602 | namespace boost { namespace python {''') | |
1603 | ||
1604 | .. @example.append(''' | |
1605 | template < | |
1606 | class A0 | |
1607 | , class A1 = parameter::void_ | |
1608 | , class A2 = parameter::void_ | |
1609 | , class A3 = parameter::void_ | |
1610 | > | |
1611 | struct class_ | |
1612 | { | |
1613 | // Create ArgumentPack | |
1614 | typedef typename | |
1615 | class_signature::bind<A0,A1,A2,A3>::type | |
1616 | args; | |
1617 | ||
1618 | // Extract first logical parameter. | |
1619 | typedef typename parameter::value_type< | |
1620 | args, tag::class_type>::type class_type; | |
1621 | ||
1622 | typedef typename parameter::value_type< | |
1623 | args, tag::base_list, bases<> >::type base_list; | |
1624 | ||
1625 | typedef typename parameter::value_type< | |
1626 | args, tag::held_type, class_type>::type held_type; | |
1627 | ||
1628 | typedef typename parameter::value_type< | |
1629 | args, tag::copyable, void>::type copyable; | |
1630 | }; | |
1631 | ||
1632 | }}''') | |
1633 | ||
1634 | It may seem like we've added a great deal of complexity, but the | |
1635 | benefits to our users are greater. Our original examples can now | |
1636 | be written without explicit parameter names: | |
1637 | ||
1638 | .. parsed-literal:: | |
1639 | ||
1640 | typedef boost::python::class_<**B**, **boost::noncopyable**> c1; | |
1641 | ||
1642 | typedef boost::python::class_<**D**, **std::auto_ptr<D>**, **bases<B>** > c2; | |
1643 | ||
1644 | .. @example.prepend(''' | |
1645 | struct B {}; | |
1646 | struct D {}; | |
1647 | ||
1648 | using boost::python::bases;''') | |
1649 | ||
1650 | .. @example.append(''' | |
1651 | BOOST_MPL_ASSERT((boost::is_same<c1::class_type, B>)); | |
1652 | BOOST_MPL_ASSERT((boost::is_same<c1::base_list, bases<> >)); | |
1653 | BOOST_MPL_ASSERT((boost::is_same<c1::held_type, B>)); | |
1654 | BOOST_MPL_ASSERT(( | |
1655 | boost::is_same<c1::copyable, boost::noncopyable> | |
1656 | )); | |
1657 | ||
1658 | BOOST_MPL_ASSERT((boost::is_same<c2::class_type, D>)); | |
1659 | BOOST_MPL_ASSERT((boost::is_same<c2::base_list, bases<B> >)); | |
1660 | BOOST_MPL_ASSERT(( | |
1661 | boost::is_same<c2::held_type, std::auto_ptr<D> > | |
1662 | )); | |
1663 | BOOST_MPL_ASSERT((boost::is_same<c2::copyable, void>));''') | |
1664 | ||
1665 | .. @test('compile', howmany='all') | |
1666 | ||
1667 | =============== | |
1668 | Advanced Topics | |
1669 | =============== | |
1670 | ||
1671 | At this point, you should have a good grasp of the basics. In this | |
1672 | section we'll cover some more esoteric uses of the library. | |
1673 | ||
1674 | ------------------------- | |
1675 | Fine-Grained Name Control | |
1676 | ------------------------- | |
1677 | ||
1678 | If you don't like the leading-underscore naming convention used | |
1679 | to refer to keyword objects, or you need the name ``tag`` for | |
1680 | something other than the keyword type namespace, there's another | |
1681 | way to use ``BOOST_PARAMETER_NAME``: | |
1682 | ||
1683 | .. parsed-literal:: | |
1684 | ||
1685 | BOOST_PARAMETER_NAME(\ **(**\ *object-name*\ **,** *tag-namespace*\ **)** *parameter-name*\ ) | |
1686 | ||
1687 | .. @ignore() | |
1688 | ||
1689 | Here is a usage example: | |
1690 | ||
1691 | .. parsed-literal:: | |
1692 | ||
1693 | BOOST_PARAMETER_NAME((**pass_foo**, **keywords**) **foo**) | |
1694 | ||
1695 | BOOST_PARAMETER_FUNCTION( | |
1696 | (int), f, | |
1697 | **keywords**, (required (**foo**, \*))) | |
1698 | { | |
1699 | return **foo** + 1; | |
1700 | } | |
1701 | ||
1702 | int x = f(**pass_foo** = 41); | |
1703 | ||
1704 | .. @example.prepend('#include <boost/parameter.hpp>') | |
1705 | .. @example.append(''' | |
1706 | int main() | |
1707 | {}''') | |
1708 | .. @test('run') | |
1709 | ||
1710 | Before you use this more verbose form, however, please read the | |
1711 | section on `best practices for keyword object naming`__. | |
1712 | ||
1713 | __ `Keyword Naming`_ | |
1714 | ||
1715 | ----------------------- | |
1716 | More |ArgumentPack|\ s | |
1717 | ----------------------- | |
1718 | ||
1719 | We've already seen |ArgumentPack|\ s when we looked at | |
1720 | `parameter-enabled constructors`_ and `class templates`__. As you | |
1721 | might have guessed, |ArgumentPack|\ s actually lie at the heart of | |
1722 | everything this library does; in this section we'll examine ways to | |
1723 | build and manipulate them more effectively. | |
1724 | ||
1725 | __ binding_intro_ | |
1726 | ||
1727 | Building |ArgumentPack|\ s | |
1728 | ========================== | |
1729 | ||
1730 | The simplest |ArgumentPack| is the result of assigning into a | |
1731 | keyword object:: | |
1732 | ||
1733 | BOOST_PARAMETER_NAME(index) | |
1734 | ||
1735 | template <class ArgumentPack> | |
1736 | int print_index(ArgumentPack const& args) | |
1737 | { | |
1738 | std::cout << "index = " << args[_index] << std::endl; | |
1739 | return 0; | |
1740 | } | |
1741 | ||
1742 | int x = print_index(_index = 3); // prints "index = 3" | |
1743 | ||
1744 | .. @example.prepend(''' | |
1745 | #include <boost/parameter.hpp> | |
1746 | #include <iostream>''') | |
1747 | ||
1748 | Also, |ArgumentPack|\ s can be composed using the comma operator. | |
1749 | The extra parentheses below are used to prevent the compiler from | |
1750 | seeing two separate arguments to ``print_name_and_index``:: | |
1751 | ||
1752 | BOOST_PARAMETER_NAME(name) | |
1753 | ||
1754 | template <class ArgumentPack> | |
1755 | int print_name_and_index(ArgumentPack const& args) | |
1756 | { | |
1757 | std::cout << "name = " << args[_name] << "; "; | |
1758 | return print_index(args); | |
1759 | } | |
1760 | ||
1761 | int y = print_name_and_index((_index = 3, _name = "jones")); | |
1762 | ||
1763 | To build an |ArgumentPack| with positional arguments, we can use a | |
1764 | |ParameterSpec|_. As introduced described in the section on `Class | |
1765 | Template Signatures`_, a |ParameterSpec| describes the positional | |
1766 | order of parameters and any associated type requirements. Just as | |
1767 | we can build an |ArgumentPack| *type* with its nested ``::bind< … | |
1768 | >`` template, we can build an |ArgumentPack| *object* by invoking | |
1769 | its function call operator: | |
1770 | ||
1771 | .. parsed-literal:: | |
1772 | ||
1773 | parameter::parameters< | |
1774 | required<tag::\ name, is_convertible<_,char const*> > | |
1775 | , optional<tag::\ index, is_convertible<_,int> > | |
1776 | > spec; | |
1777 | ||
1778 | char const sam[] = "sam"; | |
1779 | int twelve = 12; | |
1780 | ||
1781 | int z0 = print_name_and_index( **spec(**\ sam, twelve\ **)** ); | |
1782 | ||
1783 | int z1 = print_name_and_index( | |
1784 | **spec(**\ _index=12, _name="sam"\ **)** | |
1785 | ); | |
1786 | ||
1787 | .. @example.prepend(''' | |
1788 | namespace parameter = boost::parameter; | |
1789 | using parameter::required; | |
1790 | using parameter::optional; | |
1791 | using boost::is_convertible; | |
1792 | using boost::mpl::_;''') | |
1793 | ||
1794 | .. @example.append(''' | |
1795 | int main() | |
1796 | {}''') | |
1797 | ||
1798 | .. @test('run', howmany='all') | |
1799 | ||
1800 | Note that because of the `forwarding problem`_, ``parameter::parameters::operator()`` | |
1801 | can't accept non-const rvalues. | |
1802 | ||
1803 | .. _`forwarding problem`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm | |
1804 | ||
1805 | Extracting Parameter Types | |
1806 | ========================== | |
1807 | ||
1808 | If we want to know the types of the arguments passed to | |
1809 | ``print_name_and_index``, we have a couple of options. The | |
1810 | simplest and least error-prone approach is to forward them to a | |
1811 | function template and allow *it* to do type deduction:: | |
1812 | ||
1813 | BOOST_PARAMETER_NAME(name) | |
1814 | BOOST_PARAMETER_NAME(index) | |
1815 | ||
1816 | template <class Name, class Index> | |
1817 | int deduce_arg_types_impl(Name& name, Index& index) | |
1818 | { | |
1819 | Name& n2 = name; // we know the types | |
1820 | Index& i2 = index; | |
1821 | return index; | |
1822 | } | |
1823 | ||
1824 | template <class ArgumentPack> | |
1825 | int deduce_arg_types(ArgumentPack const& args) | |
1826 | { | |
1827 | return deduce_arg_types_impl(args[_name], args[_index|42]); | |
1828 | } | |
1829 | ||
1830 | .. @example.prepend(''' | |
1831 | #include <boost/parameter.hpp> | |
1832 | #include <cassert>''') | |
1833 | ||
1834 | .. @example.append(''' | |
1835 | int a1 = deduce_arg_types((_name = "foo")); | |
1836 | int a2 = deduce_arg_types((_name = "foo", _index = 3)); | |
1837 | ||
1838 | int main() | |
1839 | { | |
1840 | assert(a1 == 42); | |
1841 | assert(a2 == 3); | |
1842 | }''') | |
1843 | ||
1844 | .. @test('run') | |
1845 | ||
1846 | Occasionally one needs to deduce argument types without an extra | |
1847 | layer of function call. For example, suppose we wanted to return | |
1848 | twice the value of the ``index`` parameter? In that | |
1849 | case we can use the ``value_type< … >`` metafunction introduced | |
1850 | `earlier`__:: | |
1851 | ||
1852 | BOOST_PARAMETER_NAME(index) | |
1853 | ||
1854 | template <class ArgumentPack> | |
1855 | typename parameter::value_type<ArgumentPack, tag::index, int>::type | |
1856 | twice_index(ArgumentPack const& args) | |
1857 | { | |
1858 | return 2 * args[_index|42]; | |
1859 | } | |
1860 | ||
1861 | int six = twice_index(_index = 3); | |
1862 | ||
1863 | .. @example.prepend(''' | |
1864 | #include <boost/parameter.hpp> | |
1865 | #include <boost/type_traits/remove_reference.hpp> | |
1866 | #include <cassert> | |
1867 | ||
1868 | namespace parameter = boost::parameter; | |
1869 | ''') | |
1870 | ||
1871 | .. @example.append(''' | |
1872 | int main() | |
1873 | { | |
1874 | assert(six == 6); | |
1875 | }''') | |
1876 | ||
1877 | .. @test('run', howmany='all') | |
1878 | ||
1879 | Note that if we had used ``binding< … >`` rather than ``value_type< … | |
1880 | >``, we would end up returning a reference to the temporary created in | |
1881 | the ``2 * …`` expression. | |
1882 | ||
1883 | __ binding_intro_ | |
1884 | ||
1885 | Lazy Default Computation | |
1886 | ======================== | |
1887 | ||
1888 | When a default value is expensive to compute, it would be | |
1889 | preferable to avoid it until we're sure it's absolutely necessary. | |
1890 | ``BOOST_PARAMETER_FUNCTION`` takes care of that problem for us, but | |
1891 | when using |ArgumentPack|\ s explicitly, we need a tool other than | |
1892 | ``operator|``:: | |
1893 | ||
1894 | BOOST_PARAMETER_NAME(s1) | |
1895 | BOOST_PARAMETER_NAME(s2) | |
1896 | BOOST_PARAMETER_NAME(s3) | |
1897 | ||
1898 | template <class ArgumentPack> | |
1899 | std::string f(ArgumentPack const& args) | |
1900 | { | |
1901 | std::string const& s1 = args[_s1]; | |
1902 | std::string const& s2 = args[_s2]; | |
1903 | typename parameter::binding< | |
1904 | ArgumentPack,tag::s3,std::string | |
1905 | >::type s3 = args[_s3|(s1+s2)]; // always constructs s1+s2 | |
1906 | return s3; | |
1907 | } | |
1908 | ||
1909 | std::string x = f((_s1="hello,", _s2=" world", _s3="hi world")); | |
1910 | ||
1911 | .. @example.prepend(''' | |
1912 | #include <boost/parameter.hpp> | |
1913 | #include <string> | |
1914 | ||
1915 | namespace parameter = boost::parameter;''') | |
1916 | ||
1917 | .. @example.append(''' | |
1918 | int main() | |
1919 | {}''') | |
1920 | ||
1921 | .. @test('run') | |
1922 | ||
1923 | In the example above, the string ``"hello, world"`` is constructed | |
1924 | despite the fact that the user passed us a value for ``s3``. To | |
1925 | remedy that, we can compute the default value *lazily* (that is, | |
1926 | only on demand), by using ``boost::bind()`` to create a function | |
1927 | object. | |
1928 | ||
1929 | .. danielw: I'm leaving the text below in the source, because we might | |
1930 | .. want to change back to it after 1.34, and if I remove it now we | |
1931 | .. might forget about it. | |
1932 | ||
1933 | .. by combining the logical-or (“``||``”) operator | |
1934 | .. with a function object built by the Boost Lambda_ library: [#bind]_ | |
1935 | ||
1936 | .. parsed-literal:: | |
1937 | ||
1938 | typename parameter::binding< | |
1939 | ArgumentPack, tag::s3, std::string | |
1940 | >::type s3 = args[_s3 | |
1941 | **|| boost::bind(std::plus<std::string>(), boost::ref(s1), boost::ref(s2))** ]; | |
1942 | ||
1943 | .. @example.prepend(''' | |
1944 | #include <boost/bind.hpp> | |
1945 | #include <boost/ref.hpp> | |
1946 | #include <boost/parameter.hpp> | |
1947 | #include <string> | |
1948 | #include <functional> | |
1949 | ||
1950 | namespace parameter = boost::parameter; | |
1951 | ||
1952 | BOOST_PARAMETER_NAME(s1) | |
1953 | BOOST_PARAMETER_NAME(s2) | |
1954 | BOOST_PARAMETER_NAME(s3) | |
1955 | ||
1956 | template <class ArgumentPack> | |
1957 | std::string f(ArgumentPack const& args) | |
1958 | { | |
1959 | std::string const& s1 = args[_s1]; | |
1960 | std::string const& s2 = args[_s2];''') | |
1961 | ||
1962 | .. @example.append(''' | |
1963 | return s3; | |
1964 | } | |
1965 | ||
1966 | std::string x = f((_s1="hello,", _s2=" world", _s3="hi world")); | |
1967 | ||
1968 | int main() | |
1969 | {}''') | |
1970 | ||
1971 | .. @test('run') | |
1972 | ||
1973 | .. .. _Lambda: ../../../lambda/index.html | |
1974 | ||
1975 | .. sidebar:: Mnemonics | |
1976 | ||
1977 | To remember the difference between ``|`` and ``||``, recall that | |
1978 | ``||`` normally uses short-circuit evaluation: its second | |
1979 | argument is only evaluated if its first argument is ``false``. | |
1980 | Similarly, in ``color_map[param||f]``, ``f`` is only invoked if | |
1981 | no ``color_map`` argument was supplied. | |
1982 | ||
1983 | The expression ``bind(std::plus<std::string>(), ref(s1), ref(s2))`` yields | |
1984 | a *function object* that, when invoked, adds the two strings together. | |
1985 | That function will only be invoked if no ``s3`` argument is supplied by | |
1986 | the caller. | |
1987 | ||
1988 | .. The expression ``lambda::var(s1)+lambda::var(s2)`` yields a | |
1989 | .. *function object* that, when invoked, adds the two strings | |
1990 | .. together. That function will only be invoked if no ``s3`` argument | |
1991 | .. is supplied by the caller. | |
1992 | ||
1993 | ================ | |
1994 | Best Practices | |
1995 | ================ | |
1996 | ||
1997 | By now you should have a fairly good idea of how to use the | |
1998 | Parameter library. This section points out a few more-marginal | |
1999 | issues that will help you use the library more effectively. | |
2000 | ||
2001 | -------------- | |
2002 | Keyword Naming | |
2003 | -------------- | |
2004 | ||
2005 | ``BOOST_PARAMETER_NAME`` prepends a leading underscore to the names | |
2006 | of all our keyword objects in order to avoid the following | |
2007 | usually-silent bug: | |
2008 | ||
2009 | .. parsed-literal:: | |
2010 | ||
2011 | namespace people | |
2012 | { | |
2013 | namespace tag { struct name; struct age; } | |
2014 | ||
2015 | namespace // unnamed | |
2016 | { | |
2017 | boost::parameter::keyword<tag::name>& **name** | |
2018 | = boost::parameter::keyword<tag::name>::instance; | |
2019 | boost::parameter::keyword<tag::age>& **age** | |
2020 | = boost::parameter::keyword<tag::age>::instance; | |
2021 | } | |
2022 | ||
2023 | BOOST_PARAMETER_FUNCTION( | |
2024 | (void), g, tag, (optional (name, \*, "bob")(age, \*, 42))) | |
2025 | { | |
2026 | std::cout << name << ":" << age; | |
2027 | } | |
2028 | ||
2029 | void f(int age) | |
2030 | { | |
2031 | :vellipsis:`\ | |
2032 | . | |
2033 | . | |
2034 | . | |
2035 | ` | |
2036 | g(**age** = 3); // whoops! | |
2037 | } | |
2038 | } | |
2039 | ||
2040 | .. @ignore() | |
2041 | ||
2042 | Although in the case above, the user was trying to pass the value | |
2043 | ``3`` as the ``age`` parameter to ``g``, what happened instead | |
2044 | was that ``f``\ 's ``age`` argument got reassigned the value 3, | |
2045 | and was then passed as a positional argument to ``g``. Since | |
2046 | ``g``'s first positional parameter is ``name``, the default value | |
2047 | for ``age`` is used, and g prints ``3:42``. Our leading | |
2048 | underscore naming convention that makes this problem less likely | |
2049 | to occur. | |
2050 | ||
2051 | In this particular case, the problem could have been detected if | |
2052 | f's ``age`` parameter had been made ``const``, which is always a | |
2053 | good idea whenever possible. Finally, we recommend that you use | |
2054 | an enclosing namespace for all your code, but particularly for | |
2055 | names with leading underscores. If we were to leave out the | |
2056 | ``people`` namespace above, names in the global namespace | |
2057 | beginning with leading underscores—which are reserved to your C++ | |
2058 | compiler—might become irretrievably ambiguous with those in our | |
2059 | unnamed namespace. | |
2060 | ||
2061 | ---------- | |
2062 | Namespaces | |
2063 | ---------- | |
2064 | ||
2065 | In our examples we've always declared keyword objects in (an | |
2066 | unnamed namespace within) the same namespace as the | |
2067 | Boost.Parameter-enabled functions using those keywords: | |
2068 | ||
2069 | .. parsed-literal:: | |
2070 | ||
2071 | namespace lib | |
2072 | { | |
2073 | **BOOST_PARAMETER_NAME(name) | |
2074 | BOOST_PARAMETER_NAME(index)** | |
2075 | ||
2076 | BOOST_PARAMETER_FUNCTION( | |
2077 | (int), f, tag, | |
2078 | (optional (name,*,"bob")(index,(int),1)) | |
2079 | ) | |
2080 | { | |
2081 | std::cout << name << ":" << index << std::endl; | |
2082 | return index; | |
2083 | } | |
2084 | } | |
2085 | ||
2086 | .. @example.prepend(''' | |
2087 | #include <boost/parameter.hpp> | |
2088 | #include <iostream>''') | |
2089 | .. @namespace_setup = str(example) | |
2090 | .. @ignore() | |
2091 | ||
2092 | Users of these functions have a few choices: | |
2093 | ||
2094 | 1. Full qualification: | |
2095 | ||
2096 | .. parsed-literal:: | |
2097 | ||
2098 | int x = **lib::**\ f(**lib::**\ _name = "jill", **lib::**\ _index = 1); | |
2099 | ||
2100 | This approach is more verbose than many users would like. | |
2101 | ||
2102 | .. @example.prepend(namespace_setup) | |
2103 | .. @example.append('int main() {}') | |
2104 | .. @test('run') | |
2105 | ||
2106 | 2. Make keyword objects available through | |
2107 | *using-declarations*: | |
2108 | ||
2109 | .. parsed-literal:: | |
2110 | ||
2111 | **using lib::_name; | |
2112 | using lib::_index;** | |
2113 | ||
2114 | int x = lib::f(_name = "jill", _index = 1); | |
2115 | ||
2116 | This version is much better at the actual call site, but the | |
2117 | *using-declarations* themselves can be verbose and hard-to | |
2118 | manage. | |
2119 | ||
2120 | .. @example.prepend(namespace_setup) | |
2121 | .. @example.append('int main() {}') | |
2122 | .. @test('run') | |
2123 | ||
2124 | 3. Bring in the entire namespace with a *using-directive*: | |
2125 | ||
2126 | .. parsed-literal:: | |
2127 | ||
2128 | **using namespace lib;** | |
2129 | int x = **f**\ (_name = "jill", _index = 3); | |
2130 | ||
2131 | This option is convenient, but it indiscriminately makes the | |
2132 | *entire* contents of ``lib`` available without qualification. | |
2133 | ||
2134 | .. @example.prepend(namespace_setup) | |
2135 | .. @example.append('int main() {}') | |
2136 | .. @test('run') | |
2137 | ||
2138 | If we add an additional namespace around keyword declarations, | |
2139 | though, we can give users more control: | |
2140 | ||
2141 | .. parsed-literal:: | |
2142 | ||
2143 | namespace lib | |
2144 | { | |
2145 | **namespace keywords | |
2146 | {** | |
2147 | BOOST_PARAMETER_NAME(name) | |
2148 | BOOST_PARAMETER_NAME(index) | |
2149 | **}** | |
2150 | ||
2151 | BOOST_PARAMETER_FUNCTION( | |
2152 | (int), f, **keywords::**\ tag, | |
2153 | (optional (name,*,"bob")(index,(int),1)) | |
2154 | ) | |
2155 | { | |
2156 | std::cout << name << ":" << index << std::endl; | |
2157 | return index; | |
2158 | } | |
2159 | } | |
2160 | ||
2161 | .. @example.prepend(''' | |
2162 | #include <boost/parameter.hpp> | |
2163 | #include <iostream>''') | |
2164 | ||
2165 | Now users need only a single *using-directive* to bring in just the | |
2166 | names of all keywords associated with ``lib``: | |
2167 | ||
2168 | .. parsed-literal:: | |
2169 | ||
2170 | **using namespace lib::keywords;** | |
2171 | int y = lib::f(_name = "bob", _index = 2); | |
2172 | ||
2173 | .. @example.append('int main() {}') | |
2174 | .. @test('run', howmany='all') | |
2175 | ||
2176 | ------------- | |
2177 | Documentation | |
2178 | ------------- | |
2179 | ||
2180 | The interface idioms enabled by Boost.Parameter are completely new | |
2181 | (to C++), and as such are not served by pre-existing documentation | |
2182 | conventions. | |
2183 | ||
2184 | .. Note:: This space is empty because we haven't settled on any | |
2185 | best practices yet. We'd be very pleased to link to your | |
2186 | documentation if you've got a style that you think is worth | |
2187 | sharing. | |
2188 | ||
2189 | ============================ | |
2190 | Portability Considerations | |
2191 | ============================ | |
2192 | ||
2193 | Use the `regression test results`_ for the latest Boost release of | |
2194 | the Parameter library to see how it fares on your favorite | |
2195 | compiler. Additionally, you may need to be aware of the following | |
2196 | issues and workarounds for particular compilers. | |
2197 | ||
2198 | .. _`regression test results`: http://www.boost.org/regression/release/user/parameter.html | |
2199 | ||
2200 | ----------------- | |
2201 | No SFINAE Support | |
2202 | ----------------- | |
2203 | ||
2204 | Some older compilers don't support SFINAE. If your compiler meets | |
2205 | that criterion, then Boost headers will ``#define`` the preprocessor | |
2206 | symbol ``BOOST_NO_SFINAE``, and parameter-enabled functions won't be | |
2207 | removed from the overload set based on their signatures. | |
2208 | ||
2209 | --------------------------- | |
2210 | No Support for |result_of|_ | |
2211 | --------------------------- | |
2212 | ||
2213 | .. |result_of| replace:: ``result_of`` | |
2214 | ||
2215 | .. _result_of: ../../../utility/utility.htm#result_of | |
2216 | ||
2217 | `Lazy default computation`_ relies on the |result_of| class | |
2218 | template to compute the types of default arguments given the type | |
2219 | of the function object that constructs them. On compilers that | |
2220 | don't support |result_of|, ``BOOST_NO_RESULT_OF`` will be | |
2221 | ``#define``\ d, and the compiler will expect the function object to | |
2222 | contain a nested type name, ``result_type``, that indicates its | |
2223 | return type when invoked without arguments. To use an ordinary | |
2224 | function as a default generator on those compilers, you'll need to | |
2225 | wrap it in a class that provides ``result_type`` as a ``typedef`` | |
2226 | and invokes the function via its ``operator()``. | |
2227 | ||
2228 | .. | |
2229 | Can't Declare |ParameterSpec| via ``typedef`` | |
2230 | ============================================= | |
2231 | ||
2232 | In principle you can declare a |ParameterSpec| as a ``typedef`` | |
2233 | for a specialization of ``parameters<…>``, but Microsoft Visual C++ | |
2234 | 6.x has been seen to choke on that usage. The workaround is to use | |
2235 | inheritance and declare your |ParameterSpec| as a class: | |
2236 | ||
2237 | .. parsed-literal:: | |
2238 | ||
2239 | **struct dfs_parameters | |
2240 | :** parameter::parameters< | |
2241 | tag::graph, tag::visitor, tag::root_vertex | |
2242 | , tag::index_map, tag::color_map | |
2243 | > **{};** | |
2244 | ||
2245 | ||
2246 | Default Arguments Unsupported on Nested Templates | |
2247 | ================================================= | |
2248 | ||
2249 | As of this writing, Borland compilers don't support the use of | |
2250 | default template arguments on member class templates. As a result, | |
2251 | you have to supply ``BOOST_PARAMETER_MAX_ARITY`` arguments to every | |
2252 | use of ``parameters<…>::match``. Since the actual defaults used | |
2253 | are unspecified, the workaround is to use | |
2254 | |BOOST_PARAMETER_MATCH|_ to declare default arguments for SFINAE. | |
2255 | ||
2256 | .. |BOOST_PARAMETER_MATCH| replace:: ``BOOST_PARAMETER_MATCH`` | |
2257 | ||
2258 | -------------------------------------------------- | |
2259 | Compiler Can't See References In Unnamed Namespace | |
2260 | -------------------------------------------------- | |
2261 | ||
2262 | If you use Microsoft Visual C++ 6.x, you may find that the compiler | |
2263 | has trouble finding your keyword objects. This problem has been | |
2264 | observed, but only on this one compiler, and it disappeared as the | |
2265 | test code evolved, so we suggest you use it only as a last resort | |
2266 | rather than as a preventative measure. The solution is to add | |
2267 | *using-declarations* to force the names to be available in the | |
2268 | enclosing namespace without qualification:: | |
2269 | ||
2270 | namespace graphs | |
2271 | { | |
2272 | using graphs::graph; | |
2273 | using graphs::visitor; | |
2274 | using graphs::root_vertex; | |
2275 | using graphs::index_map; | |
2276 | using graphs::color_map; | |
2277 | } | |
2278 | ||
2279 | ================ | |
2280 | Python Binding | |
2281 | ================ | |
2282 | ||
2283 | .. _python: python.html | |
2284 | ||
2285 | Follow `this link`__ for documentation on how to expose | |
2286 | Boost.Parameter-enabled functions to Python with `Boost.Python`_. | |
2287 | ||
2288 | __ python.html | |
2289 | ||
2290 | =========== | |
2291 | Reference | |
2292 | =========== | |
2293 | ||
2294 | .. _reference: reference.html | |
2295 | ||
2296 | Follow `this link`__ to the Boost.Parameter reference | |
2297 | documentation. | |
2298 | ||
2299 | __ reference.html | |
2300 | ||
2301 | ========== | |
2302 | Glossary | |
2303 | ========== | |
2304 | ||
2305 | .. _arguments: | |
2306 | ||
2307 | :Argument (or “actual argument”): the value actually passed to a | |
2308 | function or class template | |
2309 | ||
2310 | .. _parameter: | |
2311 | ||
2312 | :Parameter (or “formal parameter”): the name used to refer to an | |
2313 | argument within a function or class template. For example, the | |
2314 | value of ``f``'s *parameter* ``x`` is given by the *argument* | |
2315 | ``3``:: | |
2316 | ||
2317 | int f(int x) { return x + 1 } | |
2318 | int y = f(3); | |
2319 | ||
2320 | ================== | |
2321 | Acknowledgements | |
2322 | ================== | |
2323 | ||
2324 | The authors would like to thank all the Boosters who participated | |
2325 | in the review of this library and its documentation, most | |
2326 | especially our review manager, Doug Gregor. | |
2327 | ||
2328 | -------------------------- | |
2329 | ||
2330 | .. [#old_interface] As of Boost 1.33.0 the Graph library was still | |
2331 | using an `older named parameter mechanism`__, but there are | |
2332 | plans to change it to use Boost.Parameter (this library) in an | |
2333 | upcoming release, while keeping the old interface available for | |
2334 | backward-compatibility. | |
2335 | ||
2336 | __ ../../../graph/doc/bgl_named_params.html | |
2337 | ||
2338 | .. [#odr] The **One Definition Rule** says that any given entity in | |
2339 | a C++ program must have the same definition in all translation | |
2340 | units (object files) that make up a program. | |
2341 | ||
2342 | .. [#vertex_descriptor] If you're not familiar with the Boost Graph | |
2343 | Library, don't worry about the meaning of any | |
2344 | Graph-library-specific details you encounter. In this case you | |
2345 | could replace all mentions of vertex descriptor types with | |
2346 | ``int`` in the text, and your understanding of the Parameter | |
2347 | library wouldn't suffer. | |
2348 | ||
2349 | .. [#ConceptCpp] This is a major motivation behind `ConceptC++`_. | |
2350 | ||
2351 | .. _`ConceptC++`: http://www.generic-programming.org/software/ConceptGCC/ | |
2352 | ||
2353 | .. .. [#bind] The Lambda library is known not to work on `some | |
2354 | .. less-conformant compilers`__. When using one of those you could | |
2355 | .. use `Boost.Bind`_ to generate the function object:: | |
2356 | ||
2357 | .. boost::bind(std::plus<std::string>(),s1,s2) | |
2358 | ||
2359 | .. [#is_keyword_expression] Here we're assuming there's a predicate | |
2360 | metafunction ``is_keyword_expression`` that can be used to | |
2361 | identify models of Boost.Python's KeywordExpression concept. | |
2362 | ||
2363 | .. .. __ http://www.boost.org/regression/release/user/lambda.html | |
2364 | .. _Boost.Bind: ../../../bind/index.html | |
2365 | ||
2366 | ||
2367 | .. [#using] You can always give the illusion that the function | |
2368 | lives in an outer namespace by applying a *using-declaration*:: | |
2369 | ||
2370 | namespace foo_overloads | |
2371 | { | |
2372 | // foo declarations here | |
2373 | void foo() { ... } | |
2374 | ... | |
2375 | } | |
2376 | using foo_overloads::foo; | |
2377 | ||
2378 | This technique for avoiding unintentional argument-dependent | |
2379 | lookup is due to Herb Sutter. | |
2380 | ||
2381 | ||
2382 | .. [#sfinae] This capability depends on your compiler's support for SFINAE. | |
2383 | **SFINAE**: **S**\ ubstitution **F**\ ailure **I**\ s | |
2384 | **N**\ ot **A**\ n **E** rror. If type substitution during the | |
2385 | instantiation of a function template results in an invalid type, | |
2386 | no compilation error is emitted; instead the overload is removed | |
2387 | from the overload set. By producing an invalid type in the | |
2388 | function signature depending on the result of some condition, | |
2389 | we can decide whether or not an overload is considered during overload | |
2390 | resolution. The technique is formalized in | |
2391 | the |enable_if|_ utility. Most recent compilers support SFINAE; | |
2392 | on compilers that don't support it, the Boost config library | |
2393 | will ``#define`` the symbol ``BOOST_NO_SFINAE``. | |
2394 | See | |
2395 | http://www.semantics.org/once_weakly/w02_SFINAE.pdf for more | |
2396 | information on SFINAE. | |
2397 | ||
2398 | .. |enable_if| replace:: ``enable_if`` | |
2399 | .. _enable_if: ../../../utility/enable_if.html | |
2400 | ||
2401 |