[parameter] Tutorial checked in

I think the tutorial documentation is close to complete. Last minute editorial comments would be appreciated. See libs/parameter/doc/html/index.html The best way to make comments is to embed them in a copy of the source: libs/parameter/doc/index.rst and post that. Don't worry about whether I'll miss the comment; I have diff tools ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:ur7dzgaw0.fsf@boost-consulting.com...
I think the tutorial documentation is close to complete. Last minute editorial comments would be appreciated. See
That's great! But It would be better if a link to complete code of tutorial be somewhere there. I'm not familiar with the implementation, but can some derivation of BOOST_AUTO be used in expression like these(at least is it possible and is it planned)?: typename parameter::binding< ArgumentPack , tag::color_map , default_color_map
::type color = args[
color_map || boost::lambda::construct<default_color_map>(num_vertices(g),i) ];
And docs stop very suddenly :) No acknoledgments, no compatibility issues, no page for headers of parameter library, and page for "might be useful" headers of other libraries... And maybe dependencies... -- Pavel Chikulaev

"Pavel Chikulaev" <pavel.chikulaev@gmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:ur7dzgaw0.fsf@boost-consulting.com...
I think the tutorial documentation is close to complete. Last minute editorial comments would be appreciated. See
That's great!
But It would be better if a link to complete code of tutorial be somewhere there.
I don't know what you mean; compilable examples, maybe? I haven't gotten around to applying my LitRe example testing and extraction system to it yet.
I'm not familiar with the implementation, but can some derivation of BOOST_AUTO be used in expression like these(at least is it possible and is it planned)?:
typename parameter::binding< ArgumentPack , tag::color_map , default_color_map
::type color = args[
color_map || boost::lambda::construct<default_color_map>(num_vertices(g),i) ];
Of course, once we have BOOST_AUTO in the CVS, something like that could be used. That *might* be worth mentioning in the tutorial someday. OTOH, the uses of BOOST_AUTO are so broad that we'd have to sprinkle "Oh, BTW, BOOST_AUTO might be useful here" throughout the documentation of many many Boost libraries.
And docs stop very suddenly :)
I only said that I was close to finishing the *tutorial*.
No acknoledgments,
I think we would like to acknowledge our review manager, but I can't think of anything else that should go in that section. Ideas?
no compatibility issues,
Compatibility issues are discussed throughout the tutorial.
no page for headers of parameter library,
That's the reference documentation; Daniel is supposedly working on it, although I haven't heard from him in a few days.
and page for "might be useful" headers of other libraries...
I have no clue what "might be useful," and none of our other libraries have such a page. I don't expect I'll be doing that, at least not for 1.33.
And maybe dependencies...
I don't think I'll be doing that either. I think bcp is the way to get that information. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:ud5pjfsi6.fsf@boost-consulting.com...
I don't know what you mean; compilable examples, maybe? And these too.
I haven't gotten around to applying my LitRe example testing and extraction system to it yet. I mean such style of familiarization with library is only for the first time, no one ever going to read it again completely, and complete code of tutorial in one place instead of scattered parts is very good when someone needs to remember all features of boost.parameter.
Of course, once we have BOOST_AUTO in the CVS, something like that could be used. That *might* be worth mentioning in the tutorial someday. OTOH, the uses of BOOST_AUTO are so broad that we'd have to sprinkle "Oh, BTW, BOOST_AUTO might be useful here" throughout the documentation of many many Boost libraries. Is it possible to add such macro now, I mean even now when we don't have boost.typeof in boost?... Something like: BOOST_AUTO_PARAMETER(ArgumentPack,color, args[
color_map || boost::lambda::construct<default_color_map>(num_vertices(g),i) ]); And It will use boost.typeof downloaded separately.
I only said that I was close to finishing the *tutorial*. :) Ok.
No acknoledgments, I think we would like to acknowledge our review manager, but I can't think of anything else that should go in that section. Ideas? Just curious.
no compatibility issues, Compatibility issues are discussed throughout the tutorial. That's not a good place them IMHO. Copy/Paste it.
no page for headers of parameter library, That's the reference documentation; Daniel is supposedly working on it, although I haven't heard from him in a few days. Ok.
and page for "might be useful" headers of other libraries... I have no clue what "might be useful," and none of our other libraries have such a page. I don't expect I'll be doing that, at least not for 1.33. The headers of other libraries you have used in your code, and maybe some other we still don't know about them...
And maybe dependencies... I don't think I'll be doing that either. I think bcp is the way to get that information. Ok.
-- Pavel Chikulaev

"Pavel Chikulaev" <pavel.chikulaev@gmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:ud5pjfsi6.fsf@boost-consulting.com...
I don't know what you mean; compilable examples, maybe? And these too.
I haven't gotten around to applying my LitRe example testing and extraction system to it yet. I mean such style of familiarization with library is only for the first time, no one ever going to read it again completely, and complete code of tutorial in one place instead of scattered parts is very good when someone needs to remember all features of boost.parameter.
Of course, once we have BOOST_AUTO in the CVS, something like that could be used. That *might* be worth mentioning in the tutorial someday. OTOH, the uses of BOOST_AUTO are so broad that we'd have to sprinkle "Oh, BTW, BOOST_AUTO might be useful here" throughout the documentation of many many Boost libraries. Is it possible to add such macro now, I mean even now when we don't have boost.typeof in boost?...
No. We're in feature freeze.
no compatibility issues, Compatibility issues are discussed throughout the tutorial. That's not a good place them IMHO. Copy/Paste it.
I'll consider doing that, thanks.
and page for "might be useful" headers of other libraries... I have no clue what "might be useful," and none of our other libraries have such a page. I don't expect I'll be doing that, at least not for 1.33. The headers of other libraries you have used in your code,
How is that different from "dependencies" you requested below?
and maybe some other we still don't know about them...
That's still way too vague for me to understand what I should write or why I should write it.
And maybe dependencies... I don't think I'll be doing that either. I think bcp is the way to get that information. Ok.
-- Pavel Chikulaev
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Dave Abrahams Boost Consulting www.boost-consulting.com

"Pavel Chikulaev" <pavel.chikulaev@gmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote:
Compatibility issues are discussed throughout the tutorial. That's not a good place them IMHO. Copy/Paste it.
I reorganized it so that they're consolidated in a single section. Thanks for all your helpful comments. -- Dave Abrahams Boost Consulting www.boost-consulting.com

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams | Sent: 15 July 2005 19:52 | To: boost@lists.boost.org | Subject: [boost] [parameter] Tutorial checked in | | | I think the tutorial documentation is close to complete. Last minute | editorial comments would be appreciated. See | | libs/parameter/doc/html/index.html | There are some funnies in several places involving “ For example, using FireFox This “fancy dance†involving the unnamed namespace and references is all done to avoid violating the One Definition Rule (ODR) ... Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com

"Paul A Bristow" <pbristow@hetp.u-net.com> writes:
| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams | Sent: 15 July 2005 19:52 | To: boost@lists.boost.org | Subject: [boost] [parameter] Tutorial checked in | | | I think the tutorial documentation is close to complete. Last minute | editorial comments would be appreciated. See | | libs/parameter/doc/html/index.html |
There are some funnies in several places involving “
For example, using FireFox
This “fancy dance†involving the unnamed namespace and references is all done to avoid violating the One Definition Rule (ODR) ...
I'm using FireFox to proof it. Is there something wrong with your browser settings that it can't display unicode characters? -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote in news:ufyuedfs6.fsf@boost-consulting.com in gmane.comp.lib.boost.devel:
For example, using FireFox
This Çœ'ª"fancy danceÇœ'ª¶ involving the unnamed namespace and references is all done to avoid violating the One Definition Rule (ODR) ... I'm using FireFox to proof it. Is there something wrong with your browser settings that it can't display unicode characters?
I also get this, in both mozilla 1.7.7 and I.E 6.0 (XP), though the souce appears to be valid UTF-8 as Notepad shows the Quotes fine. Manually changing the encoding too UTF-8 shows every thing so I looked again at the headers: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> There is a quote missing above, docutils bug ? maybe. Rob. -- http://www.victim-prime.dsl.pipex.com/

On Sat, Jul 16, 2005 at 03:59:04PM +0000, Rob Williscroft wrote:
David Abrahams wrote in news:ufyuedfs6.fsf@boost-consulting.com in gmane.comp.lib.boost.devel:
For example, using FireFox
This ǽ�'��"fancy danceǽ�'�� involving the unnamed namespace and references is all done to avoid violating the One Definition Rule (ODR) ... I'm using FireFox to proof it. Is there something wrong with your browser settings that it can't display unicode characters?
I also get this, in both mozilla 1.7.7 and I.E 6.0 (XP), though the souce appears to be valid UTF-8 as Notepad shows the Quotes fine.
Looks fine in firefox 1.0.4 and mozilla 1.7.8
Manually changing the encoding too UTF-8 shows every thing so I looked again at the headers:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
There is a quote missing above, docutils bug ? maybe.
No there isn't, charset=utf-8 is part of the content attribute's value, not a separate attribute. charset is a parameter of the content-type header. There's also an encoding attribute on the XML declaration. jon

Jonathan Wakely wrote in news:20050716165627.GA5867@compsoc.man.ac.uk in gmane.comp.lib.boost.devel:
On Sat, Jul 16, 2005 at 03:59:04PM +0000, Rob Williscroft wrote:
David Abrahams wrote in news:ufyuedfs6.fsf@boost-consulting.com in gmane.comp.lib.boost.devel:
For example, using FireFox
This Çœ'ª"fancy danceÇœ'ª¶ involving the unn amed namespace and references is all done to avoid violating the One Definition Rule (ODR) ... I'm using FireFox to proof it. Is there something wrong with your browser settings that it can't display unicode characters?
I also get this, in both mozilla 1.7.7 and I.E 6.0 (XP), though the souce appears to be valid UTF-8 as Notepad shows the Quotes fine.
Looks fine in firefox 1.0.4 and mozilla 1.7.8
Manually changing the encoding too UTF-8 shows every thing so I looked again at the headers:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8 " />
There is a quote missing above, docutils bug ? maybe.
No there isn't, charset=utf-8 is part of the content attribute's value, not a separate attribute. charset is a parameter of the content-type header. There's also an encoding attribute on the XML declaration.
Yep, your right, and if I save the file localy it display's fine but http://cvs.sourceforge.net/viewcvs.py/ *checkout*/boost/boost/libs/parameter/doc/html/index.html?rev=1.5 doesn't, so I guess its down to viewcvs.py (above) setting the HTTP Encoding header. Rob. -- http://www.victim-prime.dsl.pipex.com/

Rob Williscroft <rtw@freenet.co.uk> writes:
Yep, your right, and if I save the file localy it display's fine but
http://cvs.sourceforge.net/viewcvs.py/ *checkout*/boost/boost/libs/parameter/doc/html/index.html?rev=1.5
doesn't, so I guess its down to viewcvs.py (above) setting the HTTP Encoding header.
Yeah. Why not use http://www.boost-consulting.com/boost/libs/parameter ? -- Dave Abrahams Boost Consulting www.boost-consulting.com

Rob Williscroft <rtw@freenet.co.uk> writes:
David Abrahams wrote in news:ufyuedfs6.fsf@boost-consulting.com in gmane.comp.lib.boost.devel:
For example, using FireFox
This ǽ'ª"fancy danceǽ'ª¶ involving the unnamed namespace and references is all done to avoid violating the One Definition Rule (ODR) ... I'm using FireFox to proof it. Is there something wrong with your browser settings that it can't display unicode characters?
I also get this, in both mozilla 1.7.7 and I.E 6.0 (XP), though the souce appears to be valid UTF-8 as Notepad shows the Quotes fine.
Manually changing the encoding too UTF-8 shows every thing so I looked again at the headers:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
There is a quote missing above,
Where?
docutils bug ? maybe.
-- Dave Abrahams Boost Consulting www.boost-consulting.com

It's Firefox 1.0.4 straight 'out of the box' - downloaded of course ;-) I haven't knowingly changed any options to do with utf. But I am not a Browser expert... Paul | -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams | Sent: 16 July 2005 14:47 | To: boost@lists.boost.org | Subject: Re: [boost] [parameter] Tutorial checked in | | "Paul A Bristow" <pbristow@hetp.u-net.com> writes: | | > | > | > | -----Original Message----- | > | From: boost-bounces@lists.boost.org | > | [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams | > | Sent: 15 July 2005 19:52 | > | To: boost@lists.boost.org | > | Subject: [boost] [parameter] Tutorial checked in | > | | > | | > | I think the tutorial documentation is close to complete. | Last minute | > | editorial comments would be appreciated. See | > | | > | libs/parameter/doc/html/index.html | > | | > | > There are some funnies in several places involving “ | > | > For example, using FireFox | > | > This “fancy dance†involving the unnamed namespace and | references | > is all done to avoid violating the One Definition Rule (ODR) | > ... | | I'm using FireFox to proof it. Is there something wrong with your | browser settings that it can't display unicode characters? | | -- | Dave Abrahams | Boost Consulting | www.boost-consulting.com | | _______________________________________________ | Unsubscribe & other changes: | http://lists.boost.org/mailman/listinfo.cgi/boost |

"Paul A Bristow" <pbristow@hetp.u-net.com> writes:
It's Firefox 1.0.4 straight 'out of the box' - downloaded of course ;-)
I haven't knowingly changed any options to do with utf.
But I am not a Browser expert...
Didn't we decide this happens because CVSWeb is munging the encoding? Did you look at http://www.boost-consulting.com/boost/libs/parameter ?? -- Dave Abrahams Boost Consulting www.boost-consulting.com

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams | Sent: 18 July 2005 19:09 | To: boost@lists.boost.org | Subject: Re: [boost] [parameter] Tutorial checked in | | "Paul A Bristow" <pbristow@hetp.u-net.com> writes: | | > It's Firefox 1.0.4 straight 'out of the box' - downloaded | of course ;-) | > | > I haven't knowingly changed any options to do with utf. | > | > But I am not a Browser expert... | | Didn't we decide this happens because CVSWeb is munging the encoding? | | Did you look at http://www.boost-consulting.com/boost/libs/parameter | Yes I've just clicked Firefox 1.0.4 on this link and the following is just one example of the display problems " Important The index expression args[â¦] always yields a reference that is bound either to the actual argument passed by the caller or, if no argument is explicitly specified, to the specified default value. 2.5.2 Getting More Realistic Now it's time to put some more realistic defaults in place. We'll have to give up our print statementsâat least if we want to see the defaults workâbecause as we mentioned, the default values of these parameters generally aren't printable. " HTH Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com

Paul A Bristow wrote:
Did you look at http://www.boost-consulting.com/boost/libs/parameter
Yes I've just clicked Firefox 1.0.4 on this link and the following is just one example of the display problems
" Important
The index expression args[â?¦] always yields a reference that is bound
Confirmed. The meta tag specifies an us-ascii encoding.

"Paul A Bristow" <pbristow@hetp.u-net.com> writes:
| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams | Sent: 18 July 2005 19:09 | To: boost@lists.boost.org | Subject: Re: [boost] [parameter] Tutorial checked in | | "Paul A Bristow" <pbristow@hetp.u-net.com> writes: | | > It's Firefox 1.0.4 straight 'out of the box' - downloaded | of course ;-) | > | > I haven't knowingly changed any options to do with utf. | > | > But I am not a Browser expert... | | Didn't we decide this happens because CVSWeb is munging the encoding? | | Did you look at http://www.boost-consulting.com/boost/libs/parameter |
Yes I've just clicked Firefox 1.0.4 on this link and the following is just one example of the display problems
" Important
The index expression args[â¦] always yields a reference that is bound either to the actual argument passed by the caller or, if no argument is explicitly specified, to the specified default value.
Thanks; I repro'd the problem and now I've fixed it. Anything in unicode has to be checked into CVS as binary or it gets munged on checkout. I guess that's a problem for diff storage on the server though :( Can't wait till we switch to Subversion! -- Dave Abrahams Boost Consulting www.boost-consulting.com

From: "Paul A Bristow" <pbristow@hetp.u-net.com> | From: boost-bounces@lists.boost.org
| [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams | "Paul A Bristow" <pbristow@hetp.u-net.com> writes: | | > It's Firefox 1.0.4 straight 'out of the box' - downloaded | of course ;-) | > | Did you look at http://www.boost-consulting.com/boost/libs/parameter |
Yes I've just clicked Firefox 1.0.4 on this link and the following is just one example of the display problems
The index expression args[…] always yields a reference that is bound either to the actual argument passed by the caller or, if no argument is explicitly specified, to the specified default value.
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050511 Firefox/1.0.4" has the same problem using the URL listed above. No extensions loaded should have any effect on the display of characters, Unicode or otherwise. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

From: David Abrahams <dave@boost-consulting.com>
I think the tutorial documentation is close to complete. Last minute editorial comments would be appreciated. See
libs/parameter/doc/html/index.html
I just took a look at http://boost-consulting.com/boost/libs/parameter/doc/html/index.html and I have a few comments.
The best way to make comments is to embed them in a copy of the source:
libs/parameter/doc/index.rst
Attached. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer; ===File ~/tmp/index.rst===================================== +++++++++++++++++++++++++++++++++++++++++++++++++ The Boost Parameter Library |(logo)|__ +++++++++++++++++++++++++++++++++++++++++++++++++ .. |(logo)| image:: ../../../../boost.png :alt: Boost __ ../../../../index.htm .. Firefox, at least, seems to need some help lowering subscripts. Without the following, subscripts seem not to drop at all. .. raw:: html <style type="text/css"> sub { vertical-align: -20% } </style> ------------------------------------- :Authors: David Abrahams, Daniel Wallin :Contact: dave@boost-consulting.com, dalwan01@student.umu.se :organization: `Boost Consulting`_ :date: $Date: 2005/07/15 18:43:59 $ :copyright: Copyright David Abrahams, Daniel Wallin 2005. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) .. _`Boost Consulting`: http://www.boost-consulting.com :Abstract: Use this library to write functions that accept arguments by name: .. parsed-literal:: new_window("alert", **width=10**, **titlebar=false**); This capability is especially useful when a function has more than one argument with a useful default value, since named arguments can be passed in any order. .. _concepts: ../../../more/generic_programming.html#concept .. contents:: **Table of Contents** .. role:: concept :class: interpreted .. section-numbering:: ------------------------------------- ============== Introduction ============== In C++, arguments are normally given meaning by their positions with respect to a parameter list. That protocol is fine when there is at most one parameter with a default value, but when there are even a few useful defaults, the positional interface becomes burdensome: * Since an argument's meaning is given by its position, we have to choose an (often arbitrary) order for parameters with default values, making some combinations of defaults unusable: .. parsed-literal:: window* new_window( char const* name, **int border_width = default_border_width,** bool movable = true, bool initially_visible = true ); const bool movability = false; window* w = new_window("alert box", movability); In the example above we wanted to make an unmoveable window with a default ``border_width``, but instead we got a moveable window with a ``border_width`` of zero. To get the desired effect, we'd need to write: .. parsed-literal:: window* w = new_window( "alert box", **default_border_width**, movability); * It can become difficult for readers to understand the meaning of arguments at the call site:: window* w = new_window("alert", 1, true, false); Is this window moveable and initially invisible, or unmoveable and initially visible? The reader needs to remember the order of arguments to be sure. * The author of the call may not remember the order of the arguments either, leading to hard-to-find bugs. This library addresses the problems outlined above by associating each parameter with a keyword object. Now users can identify arguments by keyword, rather than by position: .. parsed-literal:: window* w = new_window("alert box", **movable=**\ false); // OK! .. I'm inclined to leave this part out. In particular, the 2nd point is kinda lame because even with the library, we need to introduce overloads -- dwa: C++ has two other limitations, with respect to default arguments, that are unrelated to its positional interface: * Default values cannot depend on the values of other function parameters: .. parsed-literal:: // Can we make resize windows to a square shape by default? void resize( window* w, int **width**, int height **= width** // nope, error! ); * Default values in function templates are useless for any argument whose type should be deduced when the argument is supplied explicitly:: template <class T> void f(T x = 0); f(3.14) // ok: x supplied explicitly; T is double f(); // error: can't deduce T from default argument 0! As a side effect of using the Boost Parameter library, you may find that you circumvent both of these limitations quite naturally. ========== Tutorial ========== In this section we'll show how the Parameter library can be used to build an expressive interface to the `Boost Graph library`__\ 's |dfs|_ algorithm. [#old_interface]_ After laying some groundwork and describing the algorithm's abstract interface, we'll show you how to build a basic implementation with keyword support. Then we'll add support for default arguments and we'll gradually refine the implementation with syntax improvements. Finally we'll show how to streamline the implementation of named parameter interfaces, improve their participation in overload resolution, and optimize their runtime efficiency. __ ../../../graph/index.html .. _dfs: ../../../graph/doc/depth_first_search.html .. |dfs| replace:: ``depth_first_search`` Headers And Namespaces ====================== Most components of the Parameter library are declared in a header named for the component. For example, :: #include <boost/parameter/keyword.hpp> will ensure ``boost::parameter::keyword`` is known to the compiler. There is also a combined header, ``boost/parameter.hpp``, that includes most of the library's components. For the the rest of this tutorial, unless we say otherwise, you can use the rule above to figure out which header to ``#include`` to access any given component of the library. Also, the examples below will also be written as if the namespace alias :: namespace parameter = boost::parameter; has been declared: we'll write ``parameter::xxx`` instead of ``boost::parameter::xxx``. The Abstract Interface to |dfs| =============================== The Graph library's |dfs| algorithm is a generic function accepting between one and four arguments by reference, as shown in the table below: Seeing the function described via table is harder to grasp. I suggest showing the function signature first, but omit the defaults for clarity. That will provide parameter names, in context, which will make the connection to the table simpler. .. _`parameter table`: .. _`default expressions`: .. table:: ``depth_first_search`` Parameters +----------------+----------+----------------------------------+ | Parameter Name | Dataflow | Default Value (if any) | +================+==========+==================================+ |``graph`` | in |none - this argument is required. | +----------------+----------+----------------------------------+ |``visitor`` | in |``boost::dfs_visitor<>()`` | +----------------+----------+----------------------------------+ |``root_vertex`` | in |``*vertices(graph).first`` | +----------------+----------+----------------------------------+ |``index_map`` | in |``get(boost::vertex_index,graph)``| +----------------+----------+----------------------------------+ |``color_map`` | out |an ``iterator_property_map`` | | | |created from a ``std::vector`` of | | | |``default_color_type`` of size | | | |``num_vertices(graph)`` and using | | | |the ``index_map`` for the index | | | |map. | +----------------+----------+----------------------------------+ Don't be intimidated by the complex default values. For the purposes of this exercise, you don't need to understand what they mean. Also, we'll show you how the default for ``color_map`` is computed later in the tutorial; trust us when we say that the complexity of its default will become valuable. Defining the Keywords ===================== The point of this exercise is to make it possible to call ``depth_first_search`` with keyword arguments, leaving out any arguments for which the default is appropriate: .. parsed-literal:: graphs::depth_first_search(graph, **color_map = my_color_map**); To make that syntax legal, there needs to be an object called ``color_map`` with an assignment operator that can accept a ``my_color_map`` argument. In this step we'll create one such **keyword object** for each parameter. Each keyword object will be identified by a unique **keyword tag type**. We're going to define our interface in namespace ``graphs``. Since users need access to the keyword objects, but not the tag types, we'll define the keyword objects so they're acceessible through ``graphs``, and we'll hide the tag types away in a tested namespace, ``graphs::tag``. The library provides a convenient macro for that purpose: [#msvc_keyword]_ :: #include <boost/parameter/keyword.hpp> namespace graphs { BOOST_PARAMETER_KEYWORD(tag, graph); BOOST_PARAMETER_KEYWORD(tag, visitor); BOOST_PARAMETER_KEYWORD(tag, root_vertex); BOOST_PARAMETER_KEYWORD(tag, index_map); BOOST_PARAMETER_KEYWORD(tag, color_map); } The declaration of the ``visitor`` keyword you see here is equivalent to:: namespace graphs { namespace tag { struct visitor; } namespace { boost::parameter::keyword<tag::visitor>& visitor = boost::parameter::keyword<tag::visitor>::get(); } } This \x{00E2}\x{20AC}\x{0153}fancy dance\x{00E2}\x{20AC} involving the unnamed namespace and references is all done to avoid violating the One Definition Rule (ODR) [#odr]_ when the named parameter interface is used by function templates that are instantiated in multiple translation units. Defining the Implementation Function ==================================== Next we can write the skeleton of the function that implements the core of ``depth_first_search``:: namespace graphs { namespace core { template <class ArgumentPack> void depth_first_search(ArgumentPack const& args) { // algorithm implementation goes here } }} .. |ArgumentPack| replace:: :concept:`ArgumentPack` ``core::depth_first_search`` has an |ArgumentPack| parameter: a bundle of references to the arguments that the caller passes to the algorithm, tagged with their keywords. To extract each parameter, just pass its keyword object to the |ArgumentPack|\ 's subscript operator. Just to get a feel for how things work, let's add some temporary code to print the arguments: .. parsed-literal:: namespace graphs { namespace core { template <class ArgumentPack> void depth_first_search(ArgumentPack const& args) { std::cout << "graph:\\t" << **args[graph]** << std::endl; std::cout << "visitor:\\t" << **args[visitor]** << std::endl; std::cout << "root_vertex:\\t" << **args[root_vertex]** << std::endl; std::cout << "index_map:\\t" << **args[index_map]** << std::endl; std::cout << "color_map:\\t" << **args[color_map]** << std::endl; } }} // graphs::core It's unlikely that many of the arguments the caller will eventually pass to ``depth_first_search`` can be printed, but for now the code above will give us something to experiment with. To see the keywords in action, we can write a little test driver: .. parsed-literal:: int main() { using namespace graphs; core::depth_first_search(**(** graph = 'G', visitor = 2, root_vertex = 3.5, index_map = "hello, world", color_map = false\ **)**); } An overloaded comma operator (``operator,``) combines the results of assigning to each keyword object into a single |ArgumentPack| object that gets passed on to ``core::depth_first_search``. The extra set of parentheses you see in the example above are required: without them, each assignment would be interpreted as a separate function argument and the comma operator wouldn't take effect. We'll show you how to get rid of the extra parentheses later in this tutorial. Of course, we can pass the arguments in any order:: int main() { using namespace graphs; core::depth_first_search(( root_vertex = 3.14, graph = 'G', color_map = false, index_map = "hello, world", visitor = 2)); } either of the two programs above will print:: graph: G visitor: 2 root_vertex: 3.5 index_map: hello, world color_map: false Adding Defaults =============== Currently, all the arguments to ``depth_first_search`` are required. If any parameter can't be found, there will be a compilation error where we try to extract it from the |ArgumentPack| using the subscript operator. To make it legal to omit an argument we need to give it a default value. Syntax ------ We can make any of the parameters optional by following its keyword with the ``|`` operator and the parameter's default value within the square brackets. In the following example, we've given ``root_vertex`` a default of ``42`` and ``color_map`` a default of ``"hello, world"``. .. parsed-literal:: namespace graphs { namespace core { template <class ArgumentPack> void depth_first_search(ArgumentPack const& args) { std::cout << "graph:\\t" << args[graph] << std::endl; std::cout << "visitor:\\t" << args[visitor] << std::endl; std::cout << "root_vertex:\\t" << args[root_vertex\ **|42**\ ] << std::endl; std::cout << "index_map:\\t" << args[index_map] << std::endl; std::cout << "color_map:\\t" << args[color_map\ **|"hello, world"**\ ] << std::endl; } }} // graphs::core Now we can invoke the function without supplying ``color_map`` or ``root_vertex``:: core::depth_first_search(( graph = 'G', index_map = "index", visitor = 6)); The call above would print:: graph: G visitor: 6 root_vertex: 42 index_map: index color_map: hello, world .. Important:: The index expression ``args[\x{00E2}\x{20AC}\x{00A6}]`` always yields a *reference* that is bound either to the actual argument passed by the caller or, if no argument is passed explicitly, to the specified default value. Getting More Realistic ---------------------- Now it's time to put some more realistic defaults in place. We'll have to give up our print statements\x{00E2}\x{20AC}\x{201D}at least if we want to see the defaults work\x{00E2}\x{20AC}\x{201D}since the default values of these parameters generally aren't printable. Instead, we'll connect local variables to the arguments and use those in our algorithm: .. parsed-literal:: namespace graphs { namespace core { template <class ArgumentPack> void depth_first_search(ArgumentPack const& args) { *Graph* g = args[graph]; *Visitor* v = args[visitor|\ *default-expression*\ :sub:`1`\ ]; *Vertex* s = args[root_vertex|\ *default-expression*\ :sub:`2`\ ]; *Index* i = args[index_map|\ *default-expression*\ :sub:`3`\ ]; *Color* c = args[visitor|\ *default-expression*\ :sub:`4`\ ]; *\x{00E2}\x{20AC}\x{00A6}use g, v, s, i, and c to implement the algorithm\x{00E2}\x{20AC}\x{00A6}* } }} // graphs::core We'll insert the `default expressions`_ in a moment, but first we need to come up with the types *Graph*, *Visitor*, *Vertex*, *Index*, and *Color*. The ``binding`` |Metafunction|_ ------------------------------- To compute the type of a parameter we can use a |Metafunction|_ called ``binding``: .. parsed-literal:: binding<ArgumentPack, Keyword, Default = void> { typedef *see text* type; }; where ``Default`` is the type of the default argument, if any. For example, to declare and initialize ``g`` above, we could write: .. parsed-literal:: typedef typename parameter::binding< ArgumentPack,\ **tag::graph**
::type Graph;
Graph g = args[graph]; As shown in the `parameter table`_, ``graph`` has no default, so the ``binding`` invocation for *Graph* takes only two arguments. The default ``visitor`` is ``boost::dfs_visitor<>()``, so the ``binding`` invocation for *Visitor* takes three arguments: .. parsed-literal:: typedef typename parameter::binding< ArgumentPack,\ **tag::visitor,boost::dfs_visitor<>**
::type Visitor;
Visitor v = args[visitor|\ **boost::dfs_visitor<>()**\ ]; Note that the default ``visitor`` is supplied as a *temporary* instance of ``dfs_visitor``. Because ``args[\x{00E2}\x{20AC}\x{00A6}]`` always yields a reference, making ``v`` a reference would cause it to bind to that temporary, and immediately dangle. Therefore, it's crucial that we passed ``dfs_visitor<>``, and not ``dfs_visitor<> const&``, as the last argument to ``binding``. .. Important:: Never pass ``binding`` a reference type as the default unless you know that the default value passed to the |ArgumentPack|\ 's indexing operator will outlive the reference you'll bind to it. Sometimes there's no need to use ``binding`` at all. The ``root_vertex`` argument is required to be of the graph's ``vertex_descriptor`` type, [#vertex_descriptor]_ so we can just use that knowledge to bypass ``binding`` altogether. .. parsed-literal:: typename **boost::graph_traits<Graph>::vertex_descriptor** s = args[root_vertex|\ ***vertices(g).first**\ ]; .. _dangling: .. |Metafunction| replace:: :concept:`Metafunction` .. _Metafunction: ../../../mpl/doc/refmanual/metafunction.html Beyond Ordinary Default Arguments --------------------------------- Here's how you might write the declaration for the ``index_map`` parameter: .. parsed-literal:: typedef typename parameter::binding< ArgumentPack , tag::index_map , **typename boost::property_map<Graph, vertex_index_t>::const_type**
::type Index;
Index i = args[index_map|\ **get(boost::vertex_index,g)**\ ]; Notice two capabilities we've gained over what plain C++ default arguments provide: 1. The default value of the ``index`` parameter depends on the value of the ``graph`` parameter. That's illegal in plain C++: .. parsed-literal:: void f(int **graph**, int index = **graph** + 1); // error 2. The ``index`` parameter has a useful default, yet it is templated and its type can be deduced when an ``index`` argument is explicitly specified by the caller. In plain C++, you can *specify* a default value for a parameter with deduced type, but it's not very useful: .. parsed-literal:: template <class Index> int f(Index index **= 42**); // OK int y = f(); // **error; can't deduce Index** Syntactic Refinement ==================== In this section we'll describe how you can allow callers to invoke ``depth_first_search`` with just one pair of parentheses, and to omit keywords where appropriate. Describing the Positional Argument Order ---------------------------------------- .. _ParameterSpec: .. |ParameterSpec| replace:: :concept:`ParameterSpec` First, we'll need to build a type that describes the allowed parameters and their ordering when passed positionally. This type is known as a |ParameterSpec|. [#typedef]_ :: namespace graphs { struct dfs_params : parameter::parameters< tag::graph , tag::visitor , tag::root_vertex , tag::index_map , tag::color_map > {}; } The ``parameters`` template supplies a function-call operator that groups all its arguments into an |ArgumentPack|. Any arguments passed to it without a keyword label will be associated with a parameter according to its position in the |ParameterSpec|. So for example, given an object ``p`` of type ``dfs_params``, :: p('G', index_map=1) yields an |ArgumentPack| whose ``graph`` parameter has a value of ``'G'``, and whose ``index_map`` parameter has a value of ``1``. Forwarding Functions -------------------- Next we need a family of overloaded ``depth_first_search`` function templates that can be called with anywhere from one to five arguments. These *forwarding functions* will invoke an instance of ``dfs_params`` as a function object, passing their parameters to its ``operator()`` and forwarding the result on to ``core::depth_first_search``:: namespace graphs { template <class A0> void depth_first_search(A0 const& a0) { core::depth_first_search(dfs_params()(a0)); } template <class A0, class A1> void depth_first_search(A0 const& a0, A1 const& a1) { core::depth_first_search(dfs_params()(a0,a1)); } This is hard to see: \x{00E2}\x{2039}\x{00AE} template <class A0, class A1, \x{00E2}\x{20AC}\x{00A6}class A4> void depth_first_search(A0 const& a0, A1 const& a1, \x{00E2}\x{20AC}\x{00A6}A4 const& a4) { core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4)); } } That's it! We can now call ``graphs::depth_first_search`` with from one to five arguments passed positionally or via keyword. \x{00E2}\x{20AC}\x{0153}Out\x{00E2}\x{20AC} Parameters ---------------- Well, that's not *quite* it. The overload set above works fine when ``color_map`` is passed by keyword, but it breaks down when it is passed positionally. As you may recall from the ``depth_first_search`` `parameter table`_, ``color_map`` is an \x{00E2}\x{20AC}\x{0153}out\x{00E2}\x{20AC} parameter. That means the five-argument ``depth_first_search`` overload should really take its final argument by non-``const`` reference. On the other hand, assigning into a keyword object yields a temporary |ArgumentPack| object, and *Where is this assignment occurring?* a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. To support an interface in which the last parameter is an \x{00E2}\x{20AC}\x{0153}out\x{00E2}\x{20AC} parameter, and the last argument is passed by keyword, there must be a ``depth_first_search`` overload taking its other arguments by ``const`` reference. *Why?* The simplest solution in this case is to add another overload: .. parsed-literal:: template <class A0, class A1, \x{00E2}\x{20AC}\x{00A6}class A4> void depth_first_search(A0 **const&** a0, A1 **const&** a1, \x{00E2}\x{20AC}\x{00A6}\ A4\ **&** a4) { core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4)); } That works nicely, but only because there is only one \x{00E2}\x{20AC}\x{0153}out\x{00E2}\x{20AC} parameter and it is in the last position. If ``color_map`` had been the first parameter, we would have needed *ten* overloads. In the worst case\x{00E2}\x{20AC}\x{201D}where the function has five \x{00E2}\x{20AC}\x{0153}out\x{00E2}\x{20AC} parameters\x{00E2}\x{20AC}\x{201D}2\ :sup:`5` or 32 overloads would be required. This \x{00E2}\x{20AC}\x{0153}\ `forwarding problem`_\ \x{00E2}\x{20AC} is well-known to generic library authors, and the C++ standard committee is working on a proposal__ to address it. .. _`forwarding problem`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm __ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html If it is impractical for you to write the overloads that would be required for positional \x{00E2}\x{20AC}\x{0153}out\x{00E2}\x{20AC} arguments to be passed directly, you still have the option to ask users to pass them through |ref|_, which will ensure that the algorithm implementation sees a non-``const`` reference: .. parsed-literal:: depth_first_search(g, v, s, i, **boost::ref(c)**); .. |ref| replace:: ``boost::ref`` .. _ref: http://www.boost.org/doc/html/reference_wrapper.html Generating Forwarding Functions with Macros ------------------------------------------- To remove some of the tedium of writing overloaded forwarding functions, the library supplies a macro, suitably located in ``boost/parameter/macros.hpp``, that will generate free function overloads for you:: BOOST_PARAMETER_FUN(void, depth_first_search, 1, 5, dfs_params); will generate a family of five ``depth_first_search`` overloads, in the current scope, that pass their arguments through ``dfs_params``. Instead of ``core::depth_first_search``, these overloads will forward the |ArgumentPack| on to a function called ``depth_first_search_with_named_params``, also in the current scope. It's up to you to implement that function. You could simply transplant the body of ``core::depth_first_search`` into ``depth_first_search_with_named_params`` if you were going to use this approach. Note that ``BOOST_PARAMETER_FUN`` only takes arguments by ``const`` reference, so you will have to add any additional overloads required to handle positional \x{00E2}\x{20AC}\x{0153}out\x{00E2}\x{20AC} parameters yourself. We are looking into providing a more sophisticated set of macros to address this problem and others, for an upcoming release of Boost. Controlling Overload Resolution =============================== The parameters of our templated forwarding functions are completely general; in fact, they're a perfect match for any argument type whatsoever. The problems with exposing such general function templates have been the subject of much discussion; especially in the presence of `unqualified calls`__. Probably the safest thing to do is to isolate the forwarding functions in a namespace containing no types [#using]_, but often we'd *like* our functions to play nicely with argument-dependent lookup and other function overloads. In that case, it's neccessary to remove the functions from the overload set when the passed argument types aren't appropriate. __ http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#225 This sort of overload control can be accomplished in C++ by taking advantage of the SFINAE (Substitution Failure Is Not An Error) rule. [#sfinae]_ The named parameters library provides built-in SFINAE support through the following class templates: .. parsed-literal:: template< class KeywordTag, class Predicate = *unspecified* > struct required; template< class KeywordTag, class Predicate = *unspecified* > struct optional; Instead of directly using keyword tags in our |ParameterSpec|, we can use ``required`` and ``optional`` to indicate which function parameters are required, and optionally pass ``Predicate``\ s to describe the type requirements for each function parameter. The ``Predicate`` argument must be a unary `MPL lambda expression`_ that, when applied to the actual type of the argument, indicates whether that argument type meets the function's requirements for that parameter position. .. _`MPL lambda expression`: ../../../mpl/doc/refmanual/lambda-expression.html For example, let's say we want to restrict our ``depth_first_search()`` so that the ``graph`` parameter is required and the ``root_vertex`` parameter is convertible to ``int``. We might write: .. parsed-literal:: #include <boost/type_traits/is_convertible.hpp> #include <boost/mpl/placeholders.hpp> namespace graphs { using namespace boost::mpl::placeholders; struct dfs_params : parameter::parameters< **parameter::required<tag::graph>** , parameter::optional<tag::visitor> , **parameter::optional< tag::root_vertex, boost::is_convertible<_,int> >** , parameter::optional<tag::index_map> , parameter::optional<tag::color_map> > {}; } Now we add an additional defaulted argument to each of our ``depth_first_search`` overloads to trigger SFINAE: .. parsed-literal:: namespace graphs { template <class A0> void depth_first_search( A0 const& a0 , typename dfs_params::match<A0>::type p = dfs_params()) { core::depth_first_search(**p**\ (a0)); } template <class A0, class A1> void depth_first_search( A0 const& a0, A1 const& a1 , typename dfs_params::match<A0,A1>::type p = dfs_params()) { core::depth_first_search(**p**\ (a0,a1)); } \x{00E2}\x{2039}\x{00AE} template <class A0, class A1, \x{00E2}\x{20AC}\x{00A6}class A4> void depth_first_search( A0 const& a0, A1 const& a1, \x{00E2}\x{20AC}\x{00A6}A4 const& A4 , typename dfs_params::match<A0,A1,A2,A3,A4>::type p = dfs_params()) { core::depth_first_search(**p**\ (a0,a1,a2,a3,a4)); } } These additional parameters are not intended to be used directly by callers; they merely trigger SFINAE by becoming illegal types when the ``name`` argument is not convertible to ``const char*``. The ``BOOST_PARAMETER_FUN`` macro described earlier adds these extra function parameters for you. Efficiency Issues ================= The ``color_map`` parameter gives us a few efficiency issues to consider. Here's a first cut at extraction and binding: .. parsed-literal:: typedef vector_property_map<boost::default_color_type, Index> default_color_map; typename parameter::binding< ArgumentPack , tag::color_map , default_color_map
::type color = args[color_map|\ **default_color_map(num_vertices(g),i)**\ ];
Eliminating Copies ------------------ The library has no way to know whether an explicitly-supplied argument is expensive to copy (or even if it is copyable at all), so ``binding<\x{00E2}\x{20AC}\x{00A6},k,\x{00E2}\x{20AC}\x{00A6}>::type`` is always a reference type when the *k* parameter is supplied by the caller. Since ``args[\x{00E2}\x{20AC}\x{00A6}]`` yields a reference to the actual argument, ``color`` will be bound to the actual ``color_map`` argument and no copying will be done. As described above__, because the default is a temporary, it's important that ``color`` be a non-reference when the default is used. In that case, the default value will be *copied* into ``color``. If we store the default in a named variable, though, ``color`` can be a reference, thereby eliminating the copy: .. parsed-literal:: default_color_map default_color(num_vertices(g),i); typename parameter::binding< ArgumentPack , tag::color_map , **default_color_map&**
::type color = args[color_map|default_color];
__ dangling_ .. Hint:: To avoid making needless copies, pass a *reference to the default type* as the third argument to ``binding``. Eliminating Construction ------------------------ Of course it's nice to avoid copying ``default_color``, but the more important cost is that of *constructing* it in the first place. A ``vector_property_map`` is cheap to copy, since it holds its elements via a |shared_ptr|_. On the other hand, construction of ``default_color`` costs at least two dynamic memory allocations and ``num_vertices(g)`` copies; it would be better to avoid doing this work when the default value won't be needed. .. |shared_ptr| replace:: ``shared_ptr`` .. _shared_ptr: ../../../smart_ptr/shared_ptr.htm To that end, the library allows us to supply a callable object that\x{00E2}\x{20AC}\x{201D}if no argument was supplied by the caller\x{00E2}\x{20AC}\x{201D}will be invoked to construct the default value. Instead of following the keyword with the ``|`` operator, we'll use ``||`` and follow it with a nullary (zero-argument) function object that constructs a default_color_map. Here, we build the function object using Boost.Lambda_: [#bind]_ .. _Boost.Lambda: ../../../lambda/index.html .. parsed-literal:: // After #include <boost/lambda/construct.hpp> typename parameter::binding< ArgumentPack , tag::color_map , default_color_map
::type color = args[ color_map **|| boost::lambda::construct<default_color_map>(num_vertices(g),i)** ];
.. sidebar:: Memnonics To remember the difference between ``|`` and ``||``, recall that ``||`` normally uses short-circuit evaluation: its second argument is only evaluated if its first argument is ``false``. Similarly, in ``color_map[param||f]``, ``f`` is only invoked if no ``color_map`` argument was supplied. Default Forwarding ------------------ Types that are expensive to construct yet cheap to copy aren't all that typical, and even copying the color map is more expensive than we might like. It might be nice to avoid both needless construction *and* needless copying of the default color map. The simplest way to achieve that is to avoid naming it altogether, at least not in ``core::depth_first_search``. Instead, we could just introduce another function template to implement the actual algorithm: .. parsed-literal:: namespace graphs { namespace core { template <class G, class V, class S, class I, class C> void **dfs_impl**\ (G& g, V& v, S& s, I& i, C& c) { *\x{00E2}\x{20AC}\x{00A6}actual algorithm implementation\x{00E2}\x{20AC}\x{00A6}* } }} Then, in ``core::depth_first_search``, we'll simply forward the result of indexing ``args`` to ``core::dfs_impl``:: core::dfs_impl( g,v,s,i , args[ color_map || boost::lambda::construct<default_color_map>(num_vertices(g),i) ]); In real code, after going to the trouble to write ``dfs_impl``, we'd probably just forward all the arguments. Dispatching Based on the Presence of a Default ---------------------------------------------- In fact, the Graph library itself constructs a slightly different ``color_map``, to avoid even the overhead of initializing a |shared_ptr|_:: std::vector<boost::default_color_type> color_vec(num_vertices(g)); boost::iterator_property_map< typename std::vector< boost::default_color_type >::iterator , Index
c(color_vec.begin(), i);
To avoid instantiating that code when it isn't needed, we'll have to find a way to select different function implementations, at compile time, based on whether a ``color_map`` argument was supplied. By using `tag dispatching`_ on the presence of a ``color_map`` argument, we can do just that: .. _`tag dispatching`: ../../../../more/generic_programming.html#tag_dispatching .. parsed-literal:: #include <boost/type_traits/is_same.hpp> #include <boost/mpl/bool.hpp> namespace graphs { namespace core { template <class ArgumentPack> void dfs_dispatch(ArgumentPack& args, **mpl::true_**) { *\x{00E2}\x{20AC}\x{00A6}use the color map computed in the previous example\x{00E2}\x{20AC}\x{00A6}* } template <class ArgumentPack> void dfs_dispatch(ArgumentPack& args, **mpl::false_**) { *\x{00E2}\x{20AC}\x{00A6}use args[color]\x{00E2}\x{20AC}\x{00A6}* } template <class ArgumentPack> void depth_first_search(ArgumentPack& args) { typedef typename binding<args,tag::color>::type color\_; core::dfs_dispatch(args, **boost::is_same<color\_,void>()**\ ); } }} We've used the fact that the default for ``binding``\ 's third argument is ``void``: because specializations of ``is_same`` are ``bool``-valued MPL |Integral Constant|_, it will be derived either from ``mpl::true_`` or ``mpl::false_``, and the appropriate ``dfs_dispatch`` implementation will be selected. .. |Integral Constant| replace:: :concept:`Integral Constant` .. _`Integral Constant`: ../../../mpl/doc/refmanual/integral-constant.html -------------------------- .. [#old_interface] As of Boost 1.33.0 the Graph library was still using an `older named parameter mechanism`__, but there are plans to change it to use Boost.Parameter (this library) in an upcoming release, while keeping the old interface available for backward-compatibility. __ ../../../graph/doc/bgl_named_params.html .. [#odr] The **One Definition Rule** says that any given entity in a C++ program must have the same definition in all translation units (object files) that make up a program. .. [#msvc_keyword] If you use Visual C++ 6.x, you may find you also need the following using declarations, which really should be redundant. This need has been observed, but then it disappeared as the code evolved, so add these only as a last resort:: namespace graphs { using graphs::graph; using graphs::visitor; using graphs::root_vertex; using graphs::index_map; using graphs::color_map; } .. [#vertex_descriptor] If you're not familiar with the Boost Graph Library, don't worry about the meaning of any Graph-library-specific details you encounter. In this case you could replace all mentions of vertex descriptor types with ``int`` in the text, and your understanding of the Parameter library wouldn't suffer. .. [#typedef] In principle you can also declare a |ParameterSpec| as a ``typedef``:: typedef parameter::parameters< tag::graph, tag::visitor, tag::root_vertex , tag::index_map, tag::color_map > dfs_parameters; Some older compilers seem to be happier with the use of inheritance, though. .. [#bind] The Lambda library is known not to work on `some less-conformant compilers`__. When using one of those you could define :: template <class T> struct construct2 { typedef T result_type; template <class A1, class A2> T operator() { return T(a1,a2); } }; and use Boost.Bind_ to generate the function object:: boost::bind(construct2<default_color_map>,num_vertices(g),i) .. [#using] You can always give the illusion that the function lives in an outer namespace by applying a *using-declaration*:: namespace foo_overloads { // foo declarations here void foo() { ... } ... } using foo_overloads::foo; .. [#sfinae] If type substitution during the instantiation of a function template results in an invalid type, no compilation error is emitted; instead the overload is removed from the overload set. By producing an invalid type in the function signature depending on the result of some condition, whether or not an overload is considered during overload resolution can be controlled. The technique is formalized in the |enable_if|_ utility. See http://www.semantics.org/once_weakly/w02_SFINAE.pdf for more information on SFINAE. .. |enable_if| replace:: ``enable_if`` .. _enable_if: ../../../utility/enable_if.html __ http://www.boost.org/regression/release/user/lambda.html .. _Boost.Bind: ../../../libs/bind/index.html ============================================================

Rob Stewart <stewart@sig.com> writes:
I just took a look at http://boost-consulting.com/boost/libs/parameter/doc/html/index.html and I have a few comments.
Rob, Thanks for your edits. Most were excellent and I integrated them immediately. Seeing the function described via table is harder to grasp. I suggest showing the function signature first, but omit the defaults for clarity. That will provide parameter names, in context, which will make the connection to the table simpler. I'm not sure what to do about that one. The "function signature" is a fully general function template, with an overload to handle mutable lvalues for the color_map. If you can suggest something that works, I'm open to it. I don't know what to do about the hard-to-see vertical ellipsis. Maybe just use . . . instead? You asked: *Where is this assignment occurring?* I tried to clarify: On the other hand, when passing arguments by keyword, the keyword object's assignment operator yields a temporary |ArgumentPack| object, and a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. You rewrote this section, and then also seemed confused about what it means: a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. To support an interface in which the last argument is passed by keyword, there must be a ``depth_first_search`` overload taking its argument by ``const`` reference. Here's your rewrite: a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. To support an interface in which the last parameter is an “out” parameter, and the last argument is passed by keyword, there must be a ``depth_first_search`` overload taking its other arguments by ``const`` reference. But your rewrite changes the meaning substantially. Maybe you could try to understand what I wrote or ask some more questions before we try to make it better? Thanks again for all your input, -- Dave Abrahams Boost Consulting www.boost-consulting.com

From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
I just took a look at> http://boost-consulting.com/boost/libs/parameter/doc/html/index.html> and I have a few comments. Rob, Thanks for your edits. Most were excellent and I integrated themimmediately.
I'm glad to help.
Seeing the function described via table is harder to grasp. I suggest showing the function signature first, but omit the defaults for clarity. That will provide parameter names, in context, which will make the connection to the table simpler.
I'm not sure what to do about that one. The "function signature" is afully general function template, with an overload to handle mutablelvalues for the color_map. If you can suggest something that works,I'm open to it.
I just looked at http://www.boost.org/libs/graph/doc/depth_first_search.html and didn't see a function like the one you're using. However, I can guess at what it ought to look like from your table: template < class Graph , class DFSVisitor , class Root , class ColorMap
void depth_first_search(Graph const & graph, DFSVisitor visitor, Root root_vertex, IndexMap index_map, ColorMap & color); Whether any of the other types should use references to const I can't say. Since color was described as an OUT parameter, I assumed that meant reference to non-const.
I don't know what to do about the hard-to-see vertical ellipsis.Maybe just use . . . instead?
You could use · (a.k.a. ·), but the real issue is to trigger a much larger font size.
You asked: *Where is this assignment occurring?* I tried to clarify: On the other hand, when passing arguments by keyword, the keyword object's assignment operator yields a temporary |ArgumentPack| object, and a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary.
That does it.
You rewrote this section, and then also seemed confused about what itmeans: a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. To support an interface in which the last argument is passed by keyword, there must be a ``depth_first_search`` overload taking its argument by ``const`` reference.
Here's your rewrite: a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. To support an interface in which the last parameter is an “out” parameter, and the last argument is passed by keyword, there must be a ``depth_first_search`` overload taking its other arguments by ``const`` reference.
But your rewrite changes the meaning substantially. Maybe you couldtry to understand what I wrote or ask some more questions before wetry to make it better?
Well, I thought I understood what you were trying to say, obviously, or I wouldn't have attempted the rewrite. So, let's see what your version is saying (to me). You say that there must be an "overloading taking its argument...." Note the singular. depth_first_search() takes multiple arguments, so there's an incongruity or I don't understand the overload to which you refer. To make the confusion complete, the code snippet immediately following shows this: template <class A0, class A1, \x{2026}class A4> void depth_first_search(A0 const& a0, A1 const& a1, \x{2026}A4& a4) { core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4)); } I see multiple arguments. It is notable that you've highlighted "const&" and "&" where they appear. That suggests that all of the arguments other than the last should be references to const. So, that leads to "there must be [an] overload taking its other arguments by const reference." What did I miss? -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
I just took a look at> http://boost-consulting.com/boost/libs/parameter/doc/html/index.html> and I have a few comments. Rob, Thanks for your edits. Most were excellent and I integrated themimmediately.
I'm glad to help.
Seeing the function described via table is harder to grasp. I suggest showing the function signature first, but omit the defaults for clarity. That will provide parameter names, in context, which will make the connection to the table simpler.
I'm not sure what to do about that one. The "function signature" is afully general function template, with an overload to handle mutablelvalues for the color_map. If you can suggest something that works,I'm open to it.
I just looked at http://www.boost.org/libs/graph/doc/depth_first_search.html and didn't see a function like the one you're using. However, I can guess at what it ought to look like from your table:
template < class Graph , class DFSVisitor , class Root , class ColorMap
void depth_first_search(Graph const & graph, DFSVisitor visitor, Root root_vertex, IndexMap index_map, ColorMap & color);
Whether any of the other types should use references to const I can't say. Since color was described as an OUT parameter, I assumed that meant reference to non-const.
Yeah, that's about right. No overload is needed -- I was just addled when I wrote that. The problem is, of course that while the signature above is evocative, it is not the signature of any real function we'll write. I guess I could say, "here's what the signature might be if all arguments were required..." Make sense?
I don't know what to do about the hard-to-see vertical ellipsis.Maybe just use . . . instead?
You could use · (a.k.a. ·), but the real issue is to trigger a much larger font size.
There *might* be something I could do about that. I'll have to learn a little something about css.
You asked: *Where is this assignment occurring?* I tried to clarify: On the other hand, when passing arguments by keyword, the keyword object's assignment operator yields a temporary |ArgumentPack| object, and a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary.
That does it.
Great.
You rewrote this section, and then also seemed confused about what itmeans: a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. To support an interface in which the last argument is passed by keyword, there must be a ``depth_first_search`` overload taking its argument by ``const`` reference.
Here's your rewrite: a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. To support an interface in which the last parameter is an “out” parameter, and the last argument is passed by keyword, there must be a ``depth_first_search`` overload taking its other arguments by ``const`` reference.
But your rewrite changes the meaning substantially. Maybe you couldtry to understand what I wrote or ask some more questions before wetry to make it better?
Well, I thought I understood what you were trying to say, obviously, or I wouldn't have attempted the rewrite. So, let's see what your version is saying (to me).
You say that there must be an "overloading taking its argument...." Note the singular.
Yes, note the singular! Would it help if I wrote "taking that argument" or "taking its final argument?" -- Dave Abrahams Boost Consulting www.boost-consulting.com

From: David Abrahams <dave@boost-consulting.com> I'm not quoting much because it was a mess at my end. Are you still using that utf-8 Gnus session?
Yeah, that's about right. No overload is needed -- I was just addledwhen I wrote that. The problem is, of course that while the signatureabove is evocative, it is not the signature of any real function we'llwrite. I guess I could say, "here's what the signature might be ifall arguments were required..." Make sense?
Yes.
let's see what your version is saying (to me). You say that there must be an "overloading taking its argument...." Note the singular.
Yes, note the singular! Would it help if I wrote "taking thatargument" or "taking its final argument?"
But the last argument isn't taken by reference to const. Your current wording is: To support an interface in which the last argument is passed by keyword, there must be a depth_first_search overload taking its argument by const reference. Since the overload you introduce immediately after that paragraph makes all but the last parameter be a reference to const, and the last be a reference to non-const, I'm left confused why my suggestions aren't right. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
I'm not quoting much because it was a mess at my end. Are you still using that utf-8 Gnus session?
Nope.
Yeah, that's about right. No overload is needed -- I was just addledwhen I wrote that. The problem is, of course that while the signatureabove is evocative, it is not the signature of any real function we'llwrite. I guess I could say, "here's what the signature might be ifall arguments were required..." Make sense?
Yes.
let's see what your version is saying (to me). You say that there must be an "overloading taking its argument...." Note the singular.
Yes, note the singular! Would it help if I wrote "taking thatargument" or "taking its final argument?"
But the last argument isn't taken by reference to const.
Sure it is. http://boost-consulting.com/boost/libs/parameter/doc/html/index.html#forward... clearly shows it.
Your current wording is:
To support an interface in which the last argument is passed by keyword, there must be a depth_first_search overload taking its argument by const reference.
Since the overload you introduce immediately after that paragraph makes all but the last parameter be a reference to const, and the last be a reference to non-const, I'm left confused why my suggestions aren't right.
The foregoing section has the last argument passed by const reference. Then we say it's an out parameter, so ...That means the five-argument depth_first_search overload should really take its final argument by non-const reference. Then we say On the other hand, ... there must be a depth_first_search overload taking its argument by const reference. Okay, I understand why that phrasing, followed by The simplest solution in this case is to add another overload: and the example taking a non-const reference is confusing. I'll shuffle things around. Thanks. -- Dave Abrahams Boost Consulting www.boost-consulting.com

From: David Abrahams <dave@boost-consulting.com>
David Abrahams <dave@boost-consulting.com> writes:
and the example taking a non-const reference is confusing. I'll shuffle things around.
Done.
Much better. On the other hand\x{2014}as you may recall from the parameter table\x{2014}``color_map`` is an \x{201C}out\x{201D} parameter, so it really should be passed by non-const reference. Note that "color_map" and "out" are quoted significantly differently with no apparent reason. A keyword object has a pair of operator= overloads that ensure we can pass anything by name, but when an \x{201C}out\x{201D} parameter is passed positionally, that's no help: in this case, core::depth_first_search would end up with a const reference to the color_map and compilation will fail when mutating operations are used on it. That's a long sentence and did you really mean to say "we can pass *anything*" (emphasis mine)? Perhaps this would be better: A keyword object has a pair of operator = overloads that ensure we can pass references to const or non-const objects by name, but when an "out" parameter is passed positionally, that's no help. In that case, core:;depth_first_search would end up with a...." -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
David Abrahams <dave@boost-consulting.com> writes:
and the example taking a non-const reference is confusing. I'll shuffle things around.
Done.
Much better.
On the other hand\x{2014}as you may recall from the parameter table\x{2014}``color_map`` is an \x{201C}out\x{201D} parameter, so it really should be passed by non-const reference.
Note that "color_map" and "out" are quoted significantly differently with no apparent reason.
No, ``color_map`` isn't quotation; it's markup for "code font." Look at the HTML.
A keyword object has a pair of operator= overloads that ensure we can pass anything by name, but when an \x{201C}out\x{201D} parameter is passed positionally, that's no help: in this case, core::depth_first_search would end up with a const reference to the color_map and compilation will fail when mutating operations are used on it.
That's a long sentence and did you really mean to say "we can pass *anything*" (emphasis mine)?
Yep.
Perhaps this would be better:
A keyword object has a pair of operator = overloads that ensure we can pass references to const or non-const objects by name,
You don't get to pass references to anything in C++. You pass the object referred to by a name or expression and the callee decides whether it goes by reference. Also, the point is that you can pass both lvalues and rvalues, or temporaries and non-temporaries, not that the objects can be const or non-const. You can do that just fine with a single templated function taking a T& (T will be deduced as U const when the object is constant).
but when an "out" parameter is passed positionally, that's no help. In that case, core:;depth_first_search would end up with a...."
-- Dave Abrahams Boost Consulting www.boost-consulting.com

From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
On the other hand\x{2014}as you may recall from the parameter table\x{2014}``color_map`` is an \x{201C}out\x{201D} parameter, so it really should be passed by non-const reference.
Note that "color_map" and "out" are quoted significantly differently with no apparent reason.
No, ``color_map`` isn't quotation; it's markup for "code font." Look at the HTML.
I was looking at it in the browser. I saw "``color_map``" and "<fancy open quote>out<fancy close quote>" so I saw no "code font" markup. Unless I'm misunderstanding you, something is wrong.
A keyword object has a pair of operator= overloads that ensure we can pass anything by name, but when an \x{201C}out\x{201D} parameter is passed positionally, that's no help: in this case, core::depth_first_search would end up with a const reference to the color_map and compilation will fail when mutating operations are used on it.
That's a long sentence and did you really mean to say "we can pass *anything*" (emphasis mine)?
Yep.
I didn't look, but it sounded odd that one could pass an int, char *, std::complex, etc.
Perhaps this would be better:
A keyword object has a pair of operator = overloads that ensure we can pass references to const or non-const objects by name,
You don't get to pass references to anything in C++. You pass the object referred to by a name or expression and the callee decides whether it goes by reference.
Yeah, I misspoke (miswrote?). I was referring to the parameter type when I should have been discussing the allowable argument types.
Also, the point is that you can pass both lvalues and rvalues, or temporaries and non-temporaries, not that the objects can be const or non-const. You can do that just fine with a single templated function taking a T& (T will be deduced as U const when the object is constant).
Pedantry aside, that's not the same as *anything*.
but when an "out" parameter is passed positionally, that's no help. In that case, core:;depth_first_search would end up with a...."
What about splitting the sentence into two? -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
On the other hand\x{2014}as you may recall from the parameter table\x{2014}``color_map`` is an \x{201C}out\x{201D} parameter, so it really should be passed by non-const reference.
Note that "color_map" and "out" are quoted significantly differently with no apparent reason.
No, ``color_map`` isn't quotation; it's markup for "code font." Look at the HTML.
I was looking at it in the browser. I saw "``color_map``" and "<fancy open quote>out<fancy close quote>" so I saw no "code font" markup. Unless I'm misunderstanding you, something is wrong.
Thanks, I just fixed it.
A keyword object has a pair of operator= overloads that ensure we can pass anything by name, but when an \x{201C}out\x{201D} parameter is passed positionally, that's no help: in this case, core::depth_first_search would end up with a const reference to the color_map and compilation will fail when mutating operations are used on it.
That's a long sentence and did you really mean to say "we can pass *anything*" (emphasis mine)?
Yep.
I didn't look, but it sounded odd that one could pass an int, char *, std::complex, etc.
Well, you can at least pass anything to the keyword's operator=. Whether or not the depth_first_search function compiles is another matter.
Perhaps this would be better:
A keyword object has a pair of operator = overloads that ensure we can pass references to const or non-const objects by name,
You don't get to pass references to anything in C++. You pass the object referred to by a name or expression and the callee decides whether it goes by reference.
Yeah, I misspoke (miswrote?). I was referring to the parameter type when I should have been discussing the allowable argument types.
Also, the point is that you can pass both lvalues and rvalues, or temporaries and non-temporaries, not that the objects can be const or non-const. You can do that just fine with a single templated function taking a T& (T will be deduced as U const when the object is constant).
Pedantry aside, that's not the same as *anything*.
Pedantry aside, what else is there?
but when an "out" parameter is passed positionally, that's no help. In that case, core:;depth_first_search would end up with a...."
What about splitting the sentence into two?
How's this? A keyword object has a pair of ``operator=`` overloads that ensure we can pass anything—temporary or not, ``const`` or not—by name, while preserving the mutability of non-temporaries: .. parsed-literal:: template <class A> // handles non-const, |ArgumentPack| operator=(A&); // non-temporary objects template <class A> // handles const objects |ArgumentPack| operator=(A const&); // and temporaries However, when an “out” parameter is passed positionally, there's no keyword object involved. With our ``depth_first_search`` overload set above, the ``color_map`` will be passed by ``const`` reference, and compilation will fail when mutating operations are used on it. The simple solution is to add another overload that takes a non-``const`` reference in the position of the “out” parameter: -- Dave Abrahams Boost Consulting www.boost-consulting.com

From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
I didn't look, but it sounded odd that one could pass an int,> char *, std::complex, etc.
Well, you can at least pass anything to the keyword's operator=.Whether or not the depth_first_search function compiles is anothermatter.
OK.
Pedantry aside, what else is there?
I suppose there are two levels of pedantry in this case. One is in the tutorial itself, and the other was due to my talking about passing references.
How's this? A keyword object has a pair of ``operator=`` overloads that ensure we can pass anything—temporary or not, ``const`` or not—by name, while preserving the mutability of non-temporaries: .. parsed-literal:: template <class A> // handles non-const, |ArgumentPack| operator=(A&); // non-temporary objects template <class A> // handles const objects |ArgumentPack| operator=(A const&); // and temporaries However, when an “out” parameter is passed positionally, there's no keyword object involved. With our ``depth_first_search`` overload set above, the ``color_map`` will be passed by ``const`` reference, and compilation will fail when mutating operations are used on it. The simple solution is to add another overload that takes a non-``const`` reference in the position of the “out” parameter:
That should do it! -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
You could use · (a.k.a. ·), but the real issue is to trigger a much larger font size.
Done.
Good. Now, how about pushing them farther to the left? Despite your change, it is still easy to overlook the "vertical ellipsis" and instead see only blank lines. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
You could use · (a.k.a. ·), but the real issue is to trigger a much larger font size.
Done.
Good. Now, how about pushing them farther to the left? Despite your change, it is still easy to overlook the "vertical ellipsis" and instead see only blank lines.
How far? -- Dave Abrahams Boost Consulting www.boost-consulting.com

From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
Good. Now, how about pushing them farther to the left? Despite your change, it is still easy to overlook the "vertical ellipsis" and instead see only blank lines.
How far?
It looks like this to me: template <class A0, class A1> void depth_first_search(A0 const& a0, A1 const& a1) { core::depth_first_search(dfs_params()(a0,a1)); } . . . template <class A0, class A1, \x{2026}class A4> I'd like to see something more like this: template <class A0, class A1> void depth_first_search(A0 const& a0, A1 const& a1) { core::depth_first_search(dfs_params()(a0,a1)); } . . . template <class A0, class A1, \x{2026}class A4> -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart <stewart@sig.com> writes:
From: David Abrahams <dave@boost-consulting.com>
Rob Stewart <stewart@sig.com> writes:
Good. Now, how about pushing them farther to the left? Despite your change, it is still easy to overlook the "vertical ellipsis" and instead see only blank lines.
How far?
It looks like this to me:
template <class A0, class A1> void depth_first_search(A0 const& a0, A1 const& a1) { core::depth_first_search(dfs_params()(a0,a1)); } . . . template <class A0, class A1, \x{2026}class A4>
I'd like to see something more like this:
template <class A0, class A1> void depth_first_search(A0 const& a0, A1 const& a1) { core::depth_first_search(dfs_params()(a0,a1)); } . . . template <class A0, class A1, \x{2026}class A4>
Okay. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
I think the tutorial documentation is close to complete. Last minute editorial comments would be appreciated. See libs/parameter/doc/html/index.html
Dave, I have a question about documentation of *my* library that uses Boost.Parameter. Documentation of the original new_window example is straghtforward because the public interface is exactly what the user sees and uses: window* new_window( char const* name, int border_width = default_border_width, bool movable = true, bool initially_visible = true ); However, the interface to the equivalent function that uses Boost.Parameter is extremely complex, even if the resulting usage is beautifully simple: window* w = new_window("alert box", movable=false); // OK! So, my question. How would you go about documenting this Boost.Parameter-ized interface? I guess I'm suffering from a lack of imagination, but I'm genuinely stumped by this. Perhaps you could add such a documentation to the dfs example? Regards, Angus

Angus Leeming <angus.leeming@btopenworld.com> writes:
David Abrahams wrote:
I think the tutorial documentation is close to complete. Last minute editorial comments would be appreciated. See libs/parameter/doc/html/index.html
Dave, I have a question about documentation of *my* library that uses Boost.Parameter.
Documentation of the original new_window example is straghtforward because the public interface is exactly what the user sees and uses:
window* new_window( char const* name, int border_width = default_border_width, bool movable = true, bool initially_visible = true );
However, the interface to the equivalent function that uses Boost.Parameter is extremely complex, even if the resulting usage is beautifully simple:
window* w = new_window("alert box", movable=false); // OK!
So, my question. How would you go about documenting this Boost.Parameter-ized interface?
Good question.
I guess I'm suffering from a lack of imagination, but I'm genuinely stumped by this. Perhaps you could add such a documentation to the dfs example?
Heh, well, not until we settle on a way to write it. Off the top of my head, I don't know how you'd do it. Maybe you'd show the "non-enabled" public interface as above for new_window, and establish a concept, "named parameter function object," that describes how such a non-enabled "idealized" public interface maps onto an actual enabled interface. The concept would have to establish conventions for things like whether non-templated function arguments are matched with is_same or is_convertible, for example. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Hi, A very minor change to the example code. I also see the funny chars: "... args[…] ...". I use Firefox 1.0.4 on Win2K. Adi ÿþ+++++++++++++++++++++++++++++++++++++++++++++++++ The Boost Parameter Library |(logo)|__ +++++++++++++++++++++++++++++++++++++++++++++++++ .. |(logo)| image:: ../../../../boost.png :alt: Boost __ ../../../../index.htm .. Firefox, at least, seems to need some help lowering subscripts. Without the following, subscripts seem not to drop at all. .. raw:: html <style type="text/css"> sub { vertical-align: -20% } </style> ------------------------------------- :Authors: David Abrahams, Daniel Wallin :Contact: dave@boost-consulting.com, dalwan01@student.umu.se :organization: `Boost Consulting`_ :date: $Date: 2005/07/18 20:34:31 $ :copyright: Copyright David Abrahams, Daniel Wallin 2005. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) .. _`Boost Consulting`: http://www.boost-consulting.com :Abstract: Use this library to write functions that accept arguments by name: .. parsed-literal:: new_window("alert", **width=10**, **titlebar=false**); This capability is especially useful when a function has more than one argument with a useful default value, since named arguments can be passed in any order. .. _concepts: ../../../more/generic_programming.html#concept .. contents:: **Table of Contents** .. role:: concept :class: interpreted .. section-numbering:: ------------------------------------- ============== Introduction ============== In C++, arguments are normally given meaning by their positions with respect to a parameter list. That protocol is fine when there is at most one parameter with a default value, but when there are even a few useful defaults, the positional interface becomes burdensome: * Since an argument's meaning is given by its position, we have to choose an (often arbitrary) order for parameters with default values, making some combinations of defaults unusable: .. parsed-literal:: window* new_window( char const* name, **int border_width = default_border_width,** bool movable = true, bool initially_visible = true ); const bool movability = false; window* w = new_window("alert box", movability); In the example above we wanted to make an unmoveable window with a default ``border_width``, but instead we got a moveable window with a ``border_width`` of zero. To get the desired effect, we'd need to write: .. parsed-literal:: window* w = new_window( "alert box", **default_border_width**, movability); * It can become difficult for readers to understand the meaning of arguments at the call site:: window* w = new_window("alert", 1, true, false); Is this window moveable and initially invisible, or unmoveable and initially visible? The reader needs to remember the order of arguments to be sure. * The author of the call may not remember the order of the arguments either, leading to hard-to-find bugs. This library addresses the problems outlined above by associating each parameter with a keyword object. Now users can identify arguments by keyword, rather than by position: .. parsed-literal:: window* w = new_window("alert box", **movable=**\ false); // OK! .. I'm inclined to leave this part out. In particular, the 2nd point is kinda lame because even with the library, we need to introduce overloads -- dwa: C++ has two other limitations, with respect to default arguments, that are unrelated to its positional interface: * Default values cannot depend on the values of other function parameters: .. parsed-literal:: // Can we make resize windows to a square shape by default? void resize( window* w, int **width**, int height **= width** // nope, error! ); * Default values in function templates are useless for any argument whose type should be deduced when the argument is supplied explicitly:: template <class T> void f(T x = 0); f(3.14) // ok: x supplied explicitly; T is double f(); // error: can't deduce T from default argument 0! As a side effect of using the Boost Parameter library, you may find that you circumvent both of these limitations quite naturally. ========== Tutorial ========== In this section we'll show how the Parameter library can be used to build an expressive interface to the `Boost Graph library`__\ 's |dfs|_ algorithm. [#old_interface]_ After laying some groundwork and describing the algorithm's abstract interface, we'll show you how to build a basic implementation with keyword support. Then we'll add support for default arguments and we'll gradually refine the implementation with syntax improvements. Finally we'll show how to streamline the implementation of named parameter interfaces, improve their participation in overload resolution, and optimize their runtime efficiency. __ ../../../graph/index.html .. _dfs: ../../../graph/doc/depth_first_search.html .. |dfs| replace:: ``depth_first_search`` Headers And Namespaces ====================== Most components of the Parameter library are declared in a header named for the component. For example, :: #include <boost/parameter/keyword.hpp> will ensure ``boost::parameter::keyword`` is known to the compiler. There is also a combined header, ``boost/parameter.hpp``, that includes most of the library's components. For the the rest of this tutorial, unless we say otherwise, you can use the rule above to figure out which header to ``#include`` to access any given component of the library. Also, the examples below will also be written as if the namespace alias :: namespace parameter = boost::parameter; has been declared: we'll write ``parameter::xxx`` instead of ``boost::parameter::xxx``. The Abstract Interface to |dfs| =============================== The Graph library's |dfs| algorithm is a generic function accepting from one to four arguments by reference, as shown in the table below: .. RS -- Seeing the function described via table is harder to grasp. I suggest showing the function signature first, but omit the defaults for clarity. That will provide parameter names, in context, which will make the connection to the table simpler. .. _`parameter table`: .. _`default expressions`: .. table:: ``depth_first_search`` Parameters +----------------+----------+----------------------------------+ | Parameter Name | Dataflow | Default Value (if any) | +================+==========+==================================+ |``graph`` | in |none - this argument is required. | +----------------+----------+----------------------------------+ |``visitor`` | in |``boost::dfs_visitor<>()`` | +----------------+----------+----------------------------------+ |``root_vertex`` | in |``*vertices(graph).first`` | +----------------+----------+----------------------------------+ |``index_map`` | in |``get(boost::vertex_index,graph)``| +----------------+----------+----------------------------------+ |``color_map`` | out |an ``iterator_property_map`` | | | |created from a ``std::vector`` of | | | |``default_color_type`` of size | | | |``num_vertices(graph)`` and using | | | |``index_map`` for the index map. | +----------------+----------+----------------------------------+ Don't be intimidated by the complex default values. For the purposes of this exercise, you don't need to understand what they mean. Also, we'll show you how the default for ``color_map`` is computed later in the tutorial; trust us when we say that the complexity of its default will become valuable. Defining the Keywords ===================== The point of this exercise is to make it possible to call ``depth_first_search`` with keyword arguments, leaving out any arguments for which the default is appropriate: .. parsed-literal:: graphs::depth_first_search(g, **color_map = my_color_map**); To make that syntax legal, there needs to be an object called ``color_map`` with an assignment operator that can accept a ``my_color_map`` argument. In this step we'll create one such **keyword object** for each parameter. Each keyword object will be identified by a unique **keyword tag type**. We're going to define our interface in namespace ``graphs``. Since users need access to the keyword objects, but not the tag types, we'll define the keyword objects so they're acceessible through ``graphs``, and we'll hide the tag types away in a tested namespace, ``graphs::tag``. The library provides a convenient macro for that purpose (MSVC6.x users see this note__):: #include <boost/parameter/keyword.hpp> namespace graphs { BOOST_PARAMETER_KEYWORD(tag, graph) // Note: no semicolon BOOST_PARAMETER_KEYWORD(tag, visitor) BOOST_PARAMETER_KEYWORD(tag, root_vertex) BOOST_PARAMETER_KEYWORD(tag, index_map) BOOST_PARAMETER_KEYWORD(tag, color_map) } __ `Compiler Can't See References In Unnamed Namespace`_ The declaration of the ``visitor`` keyword you see here is equivalent to:: namespace graphs { namespace tag { struct visitor; } namespace { boost::parameter::keyword<tag::visitor>& visitor = boost::parameter::keyword<tag::visitor>::get(); } } This fancy dance involving the unnamed namespace and references is all done to avoid violating the One Definition Rule (ODR) [#odr]_ when the named parameter interface is used by function templates that are instantiated in multiple translation units. Defining the Implementation Function ==================================== Next we can write the skeleton of the function that implements the core of ``depth_first_search``:: namespace graphs { namespace core { template <class ArgumentPack> void depth_first_search(ArgumentPack const& args) { // algorithm implementation goes here } }} .. |ArgumentPack| replace:: :concept:`ArgumentPack` ``core::depth_first_search`` has an |ArgumentPack| parameter: a bundle of references to the arguments that the caller passes to the algorithm, tagged with their keywords. To extract each parameter, just pass its keyword object to the |ArgumentPack|\ 's subscript operator. Just to get a feel for how things work, let's add some temporary code to print the arguments: .. parsed-literal:: namespace graphs { namespace core { template <class ArgumentPack> void depth_first_search(ArgumentPack const& args) { std::cout << "graph:\\t" << **args[graph]** << std::endl; std::cout << "visitor:\\t" << **args[visitor]** << std::endl; std::cout << "root_vertex:\\t" << **args[root_vertex]** << std::endl; std::cout << "index_map:\\t" << **args[index_map]** << std::endl; std::cout << "color_map:\\t" << **args[color_map]** << std::endl; } }} // graphs::core It's unlikely that many of the arguments the caller will eventually pass to ``depth_first_search`` can be printed, but for now the code above will give us something to experiment with. To see the keywords in action, we can write a little test driver: .. parsed-literal:: int main() { using namespace graphs; core::depth_first_search(**(** graph = 'G', visitor = 2, root_vertex = 3.5, index_map = "hello, world", color_map = false\ **)**); } An overloaded comma operator (``operator,``) combines the results of assigning to each keyword object into a single |ArgumentPack| object that gets passed on to ``core::depth_first_search``. The extra set of parentheses you see in the example above are required: without them, each assignment would be interpreted as a separate function argument and the comma operator wouldn't take effect. We'll show you how to get rid of the extra parentheses later in this tutorial. Of course, we can pass the arguments in any order:: int main() { using namespace graphs; core::depth_first_search(( root_vertex = 3.5, graph = 'G', color_map = false, index_map = "hello, world", visitor = 2)); } either of the two programs above will print:: graph: G visitor: 2 root_vertex: 3.5 index_map: hello, world color_map: false Adding Defaults =============== Currently, all the arguments to ``depth_first_search`` are required. If any parameter can't be found, there will be a compilation error where we try to extract it from the |ArgumentPack| using the subscript operator. To make it legal to omit an argument we need to give it a default value. Syntax ------ We can make any of the parameters optional by following its keyword with the ``|`` operator and the parameter's default value within the square brackets. In the following example, we've given ``root_vertex`` a default of ``42`` and ``color_map`` a default of ``"hello, world"``. .. parsed-literal:: namespace graphs { namespace core { template <class ArgumentPack> void depth_first_search(ArgumentPack const& args) { std::cout << "graph:\\t" << args[graph] << std::endl; std::cout << "visitor:\\t" << args[visitor] << std::endl; std::cout << "root_vertex:\\t" << args[root_vertex\ **|42**\ ] << std::endl; std::cout << "index_map:\\t" << args[index_map] << std::endl; std::cout << "color_map:\\t" << args[color_map\ **|"hello, world"**\ ] << std::endl; } }} // graphs::core Now we can invoke the function without supplying ``color_map`` or ``root_vertex``:: core::depth_first_search(( graph = 'G', index_map = "index", visitor = 6)); The call above would print:: graph: G visitor: 6 root_vertex: 42 index_map: index color_map: hello, world .. Important:: The index expression ``args[& ]`` always yields a *reference* that is bound either to the actual argument passed by the caller or, if no argument is passed explicitly, to the specified default value. Getting More Realistic ---------------------- Now it's time to put some more realistic defaults in place. We'll have to give up our print statements at least if we want to see the defaults work since, the default values of these parameters generally aren't printable. Instead, we'll connect local variables to the arguments and use those in our algorithm: .. parsed-literal:: namespace graphs { namespace core { template <class ArgumentPack> void depth_first_search(ArgumentPack const& args) { *Graph* g = args[graph]; *Visitor* v = args[visitor|\ *default-expression*\ :sub:`1`\ ]; *Vertex* s = args[root_vertex|\ *default-expression*\ :sub:`2`\ ]; *Index* i = args[index_map|\ *default-expression*\ :sub:`3`\ ]; *Color* c = args[visitor|\ *default-expression*\ :sub:`4`\ ]; *& use g, v, s, i, and c to implement the algorithm& * } }} // graphs::core We'll insert the `default expressions`_ in a moment, but first we need to come up with the types *Graph*, *Visitor*, *Vertex*, *Index*, and *Color*. The ``binding`` |Metafunction|_ ------------------------------- To compute the type of a parameter we can use a |Metafunction|_ called ``binding``: .. parsed-literal:: binding<ArgumentPack, Keyword, Default = void> { typedef *see text* type; }; where ``Default`` is the type of the default argument, if any. For example, to declare and initialize ``g`` above, we could write: .. parsed-literal:: typedef typename parameter::binding< ArgumentPack,\ **tag::graph**
::type Graph;
Graph g = args[graph]; As shown in the `parameter table`_, ``graph`` has no default, so the ``binding`` invocation for *Graph* takes only two arguments. The default ``visitor`` is ``boost::dfs_visitor<>()``, so the ``binding`` invocation for *Visitor* takes three arguments: .. parsed-literal:: typedef typename parameter::binding< ArgumentPack,\ **tag::visitor,boost::dfs_visitor<>**
::type Visitor;
Visitor v = args[visitor|\ **boost::dfs_visitor<>()**\ ]; Note that the default ``visitor`` is supplied as a *temporary* instance of ``dfs_visitor``. Because ``args[& ]`` always yields a reference, making ``v`` a reference would cause it to bind to that temporary, and immediately dangle. Therefore, it's crucial that we passed ``dfs_visitor<>``, and not ``dfs_visitor<> const&``, as the last argument to ``binding``. .. Important:: Never pass ``binding`` a reference type as the default unless you know that the default value passed to the |ArgumentPack|\ 's indexing operator will outlive the reference you'll bind to it. Sometimes there's no need to use ``binding`` at all. The ``root_vertex`` argument is required to be of the graph's ``vertex_descriptor`` type, [#vertex_descriptor]_ so we can just use that knowledge to bypass ``binding`` altogether. .. parsed-literal:: typename **boost::graph_traits<Graph>::vertex_descriptor** s = args[root_vertex|\ ***vertices(g).first**\ ]; .. _dangling: .. |Metafunction| replace:: :concept:`Metafunction` .. _Metafunction: ../../../mpl/doc/refmanual/metafunction.html Beyond Ordinary Default Arguments --------------------------------- Here's how you might write the declaration for the ``index_map`` parameter: .. parsed-literal:: typedef typename parameter::binding< ArgumentPack , tag::index_map , **typename boost::property_map<Graph, vertex_index_t>::const_type**
::type Index;
Index i = args[index_map|\ **get(boost::vertex_index,g)**\ ]; Notice two capabilities we've gained over what plain C++ default arguments provide: 1. The default value of the ``index`` parameter depends on the value of the ``graph`` parameter. That's illegal in plain C++: .. parsed-literal:: void f(int **graph**, int index = **graph** + 1); // error 2. The ``index`` parameter has a useful default, yet it is templated and its type can be deduced when an ``index`` argument is explicitly specified by the caller. In plain C++, you can *specify* a default value for a parameter with deduced type, but it's not very useful: .. parsed-literal:: template <class Index> int f(Index index **= 42**); // OK int y = f(); // **error; can't deduce Index** Syntactic Refinement ==================== In this section we'll describe how you can allow callers to invoke ``depth_first_search`` with just one pair of parentheses, and to omit keywords where appropriate. Describing the Positional Argument Order ---------------------------------------- .. _ParameterSpec: .. |ParameterSpec| replace:: :concept:`ParameterSpec` First, we'll need to build a type that describes the allowed parameters and their ordering when passed positionally. This type is known as a |ParameterSpec| (MSVC6.x users see this note__):: namespace graphs { typedef parameter::parameters< tag::graph , tag::visitor , tag::root_vertex , tag::index_map , tag::color_map > dfs_params; } __ `Can't Declare ParameterSpec Via typedef`_ The ``parameters`` template supplies a function-call operator that groups all its arguments into an |ArgumentPack|. Any arguments passed to it without a keyword label will be associated with a parameter according to its position in the |ParameterSpec|. So for example, given an object ``p`` of type ``dfs_params``, :: p('G', index_map=1) yields an |ArgumentPack| whose ``graph`` parameter has a value of ``'G'``, and whose ``index_map`` parameter has a value of ``1``. Forwarding Functions -------------------- Next we need a family of overloaded ``depth_first_search`` function templates that can be called with anywhere from one to five arguments. These *forwarding functions* will invoke an instance of ``dfs_params`` as a function object, passing their parameters to its ``operator()`` and forwarding the result on to ``core::depth_first_search``:: namespace graphs { template <class A0> void depth_first_search(A0 const& a0) { core::depth_first_search(dfs_params()(a0)); } template <class A0, class A1> void depth_first_search(A0 const& a0, A1 const& a1) { core::depth_first_search(dfs_params()(a0,a1)); } î" template <class A0, class A1, & class A4> void depth_first_search(A0 const& a0, A1 const& a1, & A4 const& a4) { core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4)); } } That's it! We can now call ``graphs::depth_first_search`` with from one to five arguments passed positionally or via keyword. Out Parameters ---------------- Well, that's not *quite* it. The overload set above works fine when ``color_map`` is passed by keyword, but it breaks down when it is passed positionally. As you may recall from the ``depth_first_search`` `parameter table`_, ``color_map`` is an out parameter. That means the five-argument ``depth_first_search`` overload should really take its final argument by non-``const`` reference. On the other hand, when passing arguments by keyword, the keyword object's assignment operator yields a temporary |ArgumentPack| object, and a conforming C++ compiler will refuse to bind a non-``const`` reference to a temporary. To support an interface in which the last argument is passed by keyword, there must be a ``depth_first_search`` overload taking its argument by ``const`` reference. The simplest solution in this case is to add another overload: .. parsed-literal:: template <class A0, class A1, & class A4> void depth_first_search(A0 **const&** a0, A1 **const&** a1, & \ A4\ **&** a4) { core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4)); } That works nicely, but only because there is only one out parameter and it is in the last position. If ``color_map`` had been the first parameter, we would have needed *ten* overloads. In the worst case where the function has five out parameters 2\ :sup:`5` or 32 overloads would be required. This \ `forwarding problem`_\ is well-known to generic library authors, and the C++ standard committee is working on a proposal__ to address it. .. _`forwarding problem`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm __ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html If it is impractical for you to write the overloads that would be required for positional out arguments to be passed directly, you still have the option to ask users to pass them through |ref|_, which will ensure that the algorithm implementation sees a non-``const`` reference: .. parsed-literal:: depth_first_search(g, v, s, i, **boost::ref(c)**); .. |ref| replace:: ``boost::ref`` .. _ref: http://www.boost.org/doc/html/reference_wrapper.html Generating Forwarding Functions with Macros ------------------------------------------- To remove some of the tedium of writing overloaded forwarding functions, the library supplies a macro, suitably located in ``boost/parameter/macros.hpp``, that will generate free function overloads for you:: BOOST_PARAMETER_FUN(void, depth_first_search, 1, 5, dfs_params); will generate a family of five ``depth_first_search`` overloads, in the current scope, that pass their arguments through ``dfs_params``. Instead of ``core::depth_first_search``, these overloads will forward the |ArgumentPack| on to a function called ``depth_first_search_with_named_params``, also in the current scope. It's up to you to implement that function. You could simply transplant the body of ``core::depth_first_search`` into ``depth_first_search_with_named_params`` if you were going to use this approach. Note that ``BOOST_PARAMETER_FUN`` only takes arguments by ``const`` reference, so you will have to add any additional overloads required to handle positional out parameters yourself. We are looking into providing a more sophisticated set of macros to address this problem and others, for an upcoming release of Boost. Controlling Overload Resolution =============================== The parameters of our templated forwarding functions are completely general; in fact, they're a perfect match for any argument type whatsoever. The problems with exposing such general function templates have been the subject of much discussion; especially in the presence of `unqualified calls`__. Probably the safest thing to do is to isolate the forwarding functions in a namespace containing no types [#using]_, but often we'd *like* our functions to play nicely with argument-dependent lookup and other function overloads. In that case, it's neccessary to remove the functions from the overload set when the passed argument types aren't appropriate. __ http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#225 Updating the |ParameterSpec| ---------------------------- This sort of overload control can be accomplished in C++ by taking advantage of the SFINAE (Substitution Failure Is Not An Error) rule. [#sfinae]_ You can take advantage of the Parameter library's built-in SFINAE support by using the following class templates in your |ParameterSpec|: .. parsed-literal:: template< class KeywordTag, class Predicate = *unspecified* > struct required; template< class KeywordTag, class Predicate = *unspecified* > struct optional; Instead of using keyword tags directly, we can wrap them in ``required`` and ``optional`` to indicate which function parameters are required, and optionally pass ``Predicate``\ s to describe the type requirements for each function parameter. The ``Predicate`` argument must be a unary `MPL lambda expression`_ that, when applied to the actual type of the argument, indicates whether that argument type meets the function's requirements for that parameter position. .. _`MPL lambda expression`: ../../../mpl/doc/refmanual/lambda-expression.html For example, let's say we want to restrict ``depth_first_search()`` so that the ``graph`` parameter is required and the ``root_vertex`` parameter is convertible to ``int``. We might write: .. parsed-literal:: #include <boost/type_traits/is_convertible.hpp> #include <boost/mpl/placeholders.hpp> namespace graphs { using namespace boost::mpl::placeholders; struct dfs_params : parameter::parameters< **parameter::required<tag::graph>** , parameter::optional<tag::visitor> , **parameter::optional< tag::root_vertex, boost::is_convertible<_,int> >** , parameter::optional<tag::index_map> , parameter::optional<tag::color_map> > {}; } Applying SFINAE to the Overload Set ----------------------------------- Now we add a special defaulted argument to each of our ``depth_first_search`` overloads: .. parsed-literal:: namespace graphs { template <class A0> void depth_first_search( A0 const& a0 , typename dfs_params::match<A0>::type p = dfs_params()) { core::depth_first_search(**p**\ (a0)); } template <class A0, class A1> void depth_first_search( A0 const& a0, A1 const& a1 , typename dfs_params::match<A0,A1>::type p = dfs_params()) { core::depth_first_search(**p**\ (a0,a1)); } î" template <class A0, class A1, & class A4> void depth_first_search( A0 const& a0, A1 const& a1, & A4 const& A4 , typename dfs_params::match<A0,A1,A2,A3,A4>::type p = dfs_params()) { core::depth_first_search(**p**\ (a0,a1,a2,a3,a4)); } } These additional parameters are not intended to be used directly by callers; they merely trigger SFINAE by becoming illegal types when the ``name`` argument is not convertible to ``const char*``. The ``BOOST_PARAMETER_FUN`` macro described earlier adds these extra function parameters for you (Borland users see this note__). .. _BOOST_PARAMETER_MATCH: __ `Default Arguments Unsupported on Nested Templates`_ Reducing BoilerPlate With Macros -------------------------------- The library provides a macro you can use to eliminate some of the repetetiveness of the declaring the optional parameters. ``BOOST_PARAMETER_MATCH`` takes three arguments: the |ParameterSpec|, a `Boost.Preprocessor sequence`__ of the function argument types, and a name for the defaulted function parameter (``p``, above). So we could shorten the overload set definition as follows: __ http://boost-consulting.com/mplbook/preprocessor.html#sequences .. parsed-literal:: namespace graphs { template <class A0> void depth_first_search( A0 const& a0 , **BOOST_PARAMETER_MATCH(dfs_params, (A0), p)**) { core::depth_first_search(p(a0)); } template <class A0, class A1> void depth_first_search( A0 const& a0, A1 const& a1 , **BOOST_PARAMETER_MATCH(dfs_params, (A0)(A1), p)**) { core::depth_first_search(p(a0,a1)); } î" template <class A0, class A1, & class A4> void depth_first_search( A0 const& a0, A1 const& a1, & A4 const& A4 , **BOOST_PARAMETER_MATCH(dfs_params, (A0)(A1)& (A4), p)**) { core::depth_first_search(p(a0,a1,a2,a3,a4)); } } Efficiency Issues ================= The ``color_map`` parameter gives us a few efficiency issues to consider. Here's a first cut at extraction and binding: .. parsed-literal:: typedef vector_property_map<boost::default_color_type, Index> default_color_map; typename parameter::binding< ArgumentPack , tag::color_map , default_color_map
::type color = args[color_map|\ **default_color_map(num_vertices(g),i)**\ ];
Eliminating Copies ------------------ The library has no way to know whether an explicitly-supplied argument is expensive to copy (or even if it is copyable at all), so ``binding<& ,k,& >::type`` is always a reference type when the *k* parameter is supplied by the caller. Since ``args[& ]`` yields a reference to the actual argument, ``color`` will be bound to the actual ``color_map`` argument and no copying will be done. As described above__, because the default is a temporary, it's important that ``color`` be a non-reference when the default is used. In that case, the default value will be *copied* into ``color``. If we store the default in a named variable, though, ``color`` can be a reference, thereby eliminating the copy: .. parsed-literal:: default_color_map default_color(num_vertices(g),i); typename parameter::binding< ArgumentPack , tag::color_map , **default_color_map&**
::type color = args[color_map|default_color];
__ dangling_ .. Hint:: To avoid making needless copies, pass a *reference to the default type* as the third argument to ``binding``. Lazy Default Computation ------------------------ Of course it's nice to avoid copying ``default_color``, but the more important cost is that of *constructing* it in the first place. A ``vector_property_map`` is cheap to copy, since it holds its elements via a |shared_ptr|_. On the other hand, construction of ``default_color`` costs at least two dynamic memory allocations and ``num_vertices(g)`` copies; it would be better to avoid doing this work when the default value won't be needed. .. |shared_ptr| replace:: ``shared_ptr`` .. _shared_ptr: ../../../smart_ptr/shared_ptr.htm To that end, the library allows us to supply a callable object that if no argument was supplied by the caller will be invoked to construct the default value. Instead of following the keyword with the ``|`` operator, we'll use ``||`` and follow it with a nullary (zero-argument) function object that constructs a default_color_map. Here, we build the function object using Boost.Lambda_: [#bind]_ .. _Boost.Lambda: ../../../lambda/index.html .. parsed-literal:: // After #include <boost/lambda/construct.hpp> typename parameter::binding< ArgumentPack , tag::color_map , default_color_map
::type color = args[ color_map **|| boost::lambda::construct<default_color_map>(num_vertices(g),i)** ];
.. sidebar:: Memnonics To remember the difference between ``|`` and ``||``, recall that ``||`` normally uses short-circuit evaluation: its second argument is only evaluated if its first argument is ``false``. Similarly, in ``color_map[param||f]``, ``f`` is only invoked if no ``color_map`` argument was supplied. Default Forwarding ------------------ Types that are expensive to construct yet cheap to copy aren't all that typical, and even copying the color map is more expensive than we might like. It might be nice to avoid both needless construction *and* needless copying of the default color map. The simplest way to achieve that is to avoid naming it altogether, at least not in ``core::depth_first_search``. Instead, we'll introduce another function template to implement the actual algorithm: .. parsed-literal:: namespace graphs { namespace core { template <class G, class V, class S, class I, class C> void **dfs_impl**\ (G& g, V& v, S& s, I& i, C& c) { *& actual algorithm implementation& * } }} Then, in ``core::depth_first_search``, we'll simply forward the result of indexing ``args`` to ``core::dfs_impl``:: core::dfs_impl( g,v,s,i , args[ color_map || boost::lambda::construct<default_color_map>(num_vertices(g),i) ]); In real code, after going to the trouble to write ``dfs_impl``, we'd probably just forward all the arguments. Dispatching Based on the Presence of a Default ---------------------------------------------- In fact, the Graph library itself constructs a slightly different ``color_map``, to avoid even the overhead of initializing a |shared_ptr|_:: std::vector<boost::default_color_type> color_vec(num_vertices(g)); boost::iterator_property_map< typename std::vector< boost::default_color_type >::iterator , Index
c(color_vec.begin(), i);
To avoid instantiating that code when it isn't needed, we'll have to find a way to select different function implementations, at compile time, based on whether a ``color_map`` argument was supplied. By using `tag dispatching`_ on the presence of a ``color_map`` argument, we can do just that: .. _`tag dispatching`: ../../../../more/generic_programming.html#tag_dispatching .. parsed-literal:: #include <boost/type_traits/is_same.hpp> #include <boost/mpl/bool.hpp> namespace graphs { namespace core { template <class ArgumentPack> void dfs_dispatch(ArgumentPack& args, **mpl::true_**) { *& use the color map computed in the previous example& * } template <class ArgumentPack> void dfs_dispatch(ArgumentPack& args, **mpl::false_**) { *& use args[color]& * } template <class ArgumentPack> void depth_first_search(ArgumentPack& args) { typedef typename binding<args,tag::color>::type color\_; core::dfs_dispatch(args, **boost::is_same<color\_,void>()**\ ); } }} We've used the fact that the default for ``binding``\ 's third argument is ``void``: because specializations of ``is_same`` are ``bool``-valued MPL |Integral Constant|_\ s derived either from ``mpl::true_`` or ``mpl::false_``, the appropriate ``dfs_dispatch`` implementation will be selected. .. |Integral Constant| replace:: :concept:`Integral Constant` .. _`Integral Constant`: ../../../mpl/doc/refmanual/integral-constant.html ============================ Portability Considerations ============================ Use the `regression test results`_ for the latest Boost release of the Parameter library to see how it fares on your favorite compiler. Additionally, you may need to be aware of the following issues and workarounds for particular compilers. .. _`regression test results`: http://www.boost.org/regression/release/user/parameter.html No SFINAE Support ================= Some older compilers don't support SFINAE. If your compiler meets that criterion, then Boost headers will ``#define`` the preprocessor symbol ``BOOST_NO_SFINAE``, and uses of ``parameters<& >::match`` and |BOOST_PARAMETER_MATCH| will be harmless, but will have no effect. No Support for |result_of|_ =========================== .. |result_of| replace:: ``result_of`` .. _result_of: ../../../utility/utility.htm#result_of `Lazy default computation`_ relies on the |result_of| class template to compute the types of default arguments given the type of the function object that constructs them. On compilers that don't support |result_of|, ``BOOST_NO_RESULT_OF`` will be ``#define``\ d, and the compiler will expect the function object to contain a nested type name, ``result_type``, that indicates its return type when invoked without arguments. To use an ordinary function as a default generator on those compilers, you'll need to wrap it in a class that provides ``result_type`` as a ``typedef`` and invokes the function via its ``operator()``. Can't Declare |ParameterSpec| via ``typedef`` ============================================= In principle you can declare a |ParameterSpec| as a ``typedef`` for a specialization of ``parameters<& >``, but Microsoft Visual C++ 6.x has been seen to choke on that usage. The workaround is to use inheritance and declare your |ParameterSpec| as a class: .. parsed-literal:: **struct dfs_parameters :** parameter::parameters< tag::graph, tag::visitor, tag::root_vertex , tag::index_map, tag::color_map > **{};** Default Arguments Unsupported on Nested Templates ================================================= As of this writing, Borland compilers don't support the use of default template arguments on member class templates. As a result, you have to supply ``BOOST_PARAMETER_MAX_ARITY`` arguments to every use of ``parameters<& >::match``. Since the actual defaults used are unspecified, the workaround is to use |BOOST_PARAMETER_MATCH|_ to declare default arguments for SFINAE. .. |BOOST_PARAMETER_MATCH| replace:: ``BOOST_PARAMETER_MATCH`` Compiler Can't See References In Unnamed Namespace ================================================== If you use Microsoft Visual C++ 6.x, you may find that the compiler has trouble finding your keyword objects. This problem has been observed, but only on this one compiler, and it disappeared as the test code evolved, so we suggest you use it only as a last resort rather than as a preventative measure. The solution is to add *using-declarations* to force the names to be available in the enclosing namespace without qualification:: namespace graphs { using graphs::graph; using graphs::visitor; using graphs::root_vertex; using graphs::index_map; using graphs::color_map; } -------------------------- .. [#old_interface] As of Boost 1.33.0 the Graph library was still using an `older named parameter mechanism`__, but there are plans to change it to use Boost.Parameter (this library) in an upcoming release, while keeping the old interface available for backward-compatibility. __ ../../../graph/doc/bgl_named_params.html .. [#odr] The **One Definition Rule** says that any given entity in a C++ program must have the same definition in all translation units (object files) that make up a program. .. [#vertex_descriptor] If you're not familiar with the Boost Graph Library, don't worry about the meaning of any Graph-library-specific details you encounter. In this case you could replace all mentions of vertex descriptor types with ``int`` in the text, and your understanding of the Parameter library wouldn't suffer. .. [#bind] The Lambda library is known not to work on `some less-conformant compilers`__. When using one of those you could define :: template <class T> struct construct2 { typedef T result_type; template <class A1, class A2> T operator() { return T(a1,a2); } }; and use Boost.Bind_ to generate the function object:: boost::bind(construct2<default_color_map>,num_vertices(g),i) __ http://www.boost.org/regression/release/user/lambda.html .. _Boost.Bind: ../../../libs/bind/index.html .. [#using] You can always give the illusion that the function lives in an outer namespace by applying a *using-declaration*:: namespace foo_overloads { // foo declarations here void foo() { ... } ... } using foo_overloads::foo; .. [#sfinae] If type substitution during the instantiation of a function template results in an invalid type, no compilation error is emitted; instead the overload is removed from the overload set. By producing an invalid type in the function signature depending on the result of some condition, whether or not an overload is considered during overload resolution can be controlled. The technique is formalized in the |enable_if|_ utility. See http://www.semantics.org/once_weakly/w02_SFINAE.pdf for more information on SFINAE. .. |enable_if| replace:: ``enable_if`` .. _enable_if: ../../../utility/enable_if.html

On Tue, Jul 19, 2005 at 12:53:10AM +0300, Adi Shavit wrote:
Hi,
A very minor change to the example code. I also see the funny chars: "... args[???] ...". I use Firefox 1.0.4 on Win2K.
Again: Are you looking at the file from SourceForge's web interface? If so, that is why you see the UTF-8 characters mangled. Try saving the file to disk then viewing it, or viewing it on boost-consulting.com. jon

Adi Shavit <adish@gentech.co.il> writes:
Hi,
A very minor change to the example code.
After saving the attachment and interpreting it with a utf-16-dos coding system (whew!), I saw one change: 3.14 -> 3.5 Thanks; good eye.
I also see the funny chars: "... args[…] ...". I use Firefox 1.0.4 on Win2K.
What URL are you looking at? -- Dave Abrahams Boost Consulting www.boost-consulting.com

Hi,
After saving the attachment and interpreting it with a utf-16-dos coding system (whew!), I saw one change:
3.14 -> 3.5
Thanks; good eye.
Yeah, I said it was very minor. I saved it with notepad Unicode, due to those strange little characters.
What URL are you looking at?
I used http://boost-consulting.com/boost/libs/parameter/doc/html/ with FireFox 1.0.4, but funnily enough they now show properly. Keep up the great work, Adi <going back to lurk mode...>

Adi Shavit <adish@gentech.co.il> writes:
Hi,
After saving the attachment and interpreting it with a utf-16-dos coding system (whew!), I saw one change:
3.14 -> 3.5
Thanks; good eye.
Yeah, I said it was very minor. I saved it with notepad Unicode, due to those strange little characters.
Well, FWIW, that changed the encoding and your mailer wasn't kind enough to note that in the MIME for the attachment.
What URL are you looking at?
I used http://boost-consulting.com/boost/libs/parameter/doc/html/ with FireFox 1.0.4, but funnily enough they now show properly.
Keep up the great work,
:) -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (9)
-
Adi Shavit
-
Angus Leeming
-
David Abrahams
-
Jonathan Wakely
-
Paul A Bristow
-
Pavel Chikulaev
-
Peter Dimov
-
Rob Stewart
-
Rob Williscroft