*** empty log message ***

[SVN r1889]
This commit is contained in:
Dave Abrahams
2004-01-17 00:47:18 +00:00
parent 62da7331a2
commit f7f276637c

444
doc/named_params.html Executable file
View File

@@ -0,0 +1,444 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.3.1: http://docutils.sourceforge.net/" />
<title>The Boost.NamedParams Library Boost</title>
<link rel="stylesheet" href="../../../rst.css" type="text/css" />
</head>
<body>
<div class="document" id="the-boost-namedparams-library-logo">
<h1 class="title">The Boost.NamedParams Library <a class="reference" href="../../../index.htm"><img alt="Boost" src="../../../c++boost.gif" /></a></h1>
<hr />
<table class="field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">Authors:</th><td class="field-body">David Abrahams, Daniel Wallin</td>
</tr>
<tr class="field"><th class="field-name">Contact:</th><td class="field-body"><a class="reference" href="mailto:dave&#64;boost-consulting.com">dave&#64;boost-consulting.com</a>, <a class="reference" href="mailto:dalwan01&#64;student.umu.se">dalwan01&#64;student.umu.se</a></td>
</tr>
<tr class="field"><th class="field-name">organizations:</th><td class="field-body"><a class="reference" href="http://www.boost-consulting.com">Boost Consulting</a>,</td>
</tr>
<tr class="field"><th class="field-name">date:</th><td class="field-body">$Date$</td>
</tr>
<tr class="field"><th class="field-name">copyright:</th><td class="field-body">Copyright David Abrahams, Daniel Wallin 2003.</td>
</tr>
<tr class="field"><th class="field-name">license:</th><td class="field-body">Use, modification and distribution is subject to the
Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at
<a class="reference" href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</td>
</tr>
</tbody>
</table>
<div class="contents topic" id="outline">
<p class="topic-title"><a name="outline">Outline</a></p>
<ul class="auto-toc simple">
<li><a class="reference" href="#introduction" id="id7" name="id7">1   Introduction</a></li>
<li><a class="reference" href="#tutorial" id="id8" name="id8">2   Tutorial</a><ul class="auto-toc">
<li><a class="reference" href="#defining-the-keywords" id="id9" name="id9">2.1   Defining the keywords</a></li>
<li><a class="reference" href="#defining-the-forwarding-functions" id="id10" name="id10">2.2   Defining the forwarding functions</a></li>
<li><a class="reference" href="#defining-the-implementation-function" id="id11" name="id11">2.3   Defining the implementation function</a></li>
</ul>
</li>
<li><a class="reference" href="#limitations-of-the-approach" id="id12" name="id12">3   Limitations of the Approach</a></li>
<li><a class="reference" href="#controlling-overload-resolution" id="id13" name="id13">4   Controlling Overload Resolution</a></li>
<li><a class="reference" href="#lazy-evaluation-of-defaults" id="id14" name="id14">5   Lazy Evaluation of Defaults</a></li>
<li><a class="reference" href="#automatic-overload-generation" id="id15" name="id15">6   Automatic Overload Generation</a></li>
<li><a class="reference" href="#portability" id="id16" name="id16">7   Portability</a></li>
</ul>
</div>
<div class="section" id="introduction">
<h1><a class="toc-backref" href="#id7" name="introduction">1   Introduction</a></h1>
<p>In C++ function arguments are given meaning by their position in
the parameter list. This protocol is fine when there are few
parameters with default values, but as the number of parameters
grows, so does the inconvenience of passing arguments in the
correct order, especially in the presence of default values:</p>
<blockquote>
<ul>
<li><p class="first">It can become difficult for readers to understand the meaning of
arguments at the call site:</p>
<pre class="literal-block">
window* w = new_window(&quot;alert&quot;, true, true, false, 77, 65);
</pre>
</li>
<li><p class="first">Since meaning is given by position, we have to choose some
(often arbitrary) order for parameters with default values,
making some combinations of defaults unusable:</p>
<pre class="literal-block">
window* new_window(
char const* name, bool border = true
, bool opaque = true, bool movable = false
, int width = 100, int height = 100);
const bool movability = true;
window* w = new_window(&quot;alert2&quot;, movability); // error!
</pre>
</li>
<li><p class="first">Default values can not depend on the values of other function
parameters:</p>
<pre class="literal-block">
window* new_window(
char const* name, bool border, ...
, int width = 100, int heigh = width); // error!
</pre>
</li>
<li><p class="first">Template types can not be deduced from the default values, so
we have to resort to overloading to provide default values for
parameters with template type:</p>
<pre class="literal-block">
template&lt;class T&gt; void f(T x = 0);
f(); // error!
</pre>
</li>
</ul>
</blockquote>
<p>This library is an attempt to address the problems outlined above
by associating each parameter with a keyword identifier. Using
this library, users can identify parameters by name instead of just
argument position:</p>
<pre class="literal-block">
window* w = new_window(&quot;alert2&quot;, movable = movability); // OK!
</pre>
<!-- DWA Daniel, we explicitly *don't* need ref() for the case
described below. It's only when we want to pass by reference
without a keyword that we need it.
You also can't start talking about forwarding functions without
introducing them first!
The tutorial has to come before all the nasty details below.
I'm going to comment on that and leave the next stuff alone -->
</div>
<div class="section" id="tutorial">
<h1><a class="toc-backref" href="#id8" name="tutorial">2   Tutorial</a></h1>
<!-- DWA you need some set-up here describing the problem you're
going to solve. -->
<p>This example shows how to wrap a function:</p>
<pre class="literal-block">
void foo(char const* name, float value);
</pre>
<p>to give both parameters names and default values.</p>
<div class="section" id="defining-the-keywords">
<h2><a class="toc-backref" href="#id9" name="defining-the-keywords">2.1   Defining the keywords</a></h2>
<p>First we define the named parameter keywords. This is done by creating
&quot;tag&quot; types for each keyword, and declaring <tt class="literal"><span class="pre">keyword&lt;</span></tt><em>tag</em><tt class="literal"><span class="pre">&gt;</span></tt> objects:</p>
<pre class="literal-block">
#include &lt;boost/named_params.hpp&gt;
struct name_t; // tag types
struct value_t;
namespace {
boost::keyword&lt;name_t&gt; name; // keyword objects
boost::keyword&lt;value_t&gt; value;
}
</pre>
<p>Placing these keyword objects in an unnamed namespace will prevent
link errors when you declare keywords in header files [<strong>Note</strong>:
the tag types should generally <em>not</em> be declared in an unnamed
namespace]. We also need to create a keywords list for our
function. These keywords should be declared in the same order as
their corresponding parameters appear in the function's parameter
list:</p>
<pre class="literal-block">
struct foo_keywords
: boost::keywords&lt;
name_t
, value_t
&gt;
{};
</pre>
</div>
<div class="section" id="defining-the-forwarding-functions">
<h2><a class="toc-backref" href="#id10" name="defining-the-forwarding-functions">2.2   Defining the forwarding functions</a></h2>
<pre class="literal-block">
template&lt;class Params&gt;
void foo_impl(const Params&amp;);
void foo()
{
foo_impl(foo_keywords());
}
template&lt;class A0&gt;
void foo(const A0&amp; a0)
{
foo_impl(foo_keywords(a0));
}
template&lt;class A0, class A1&gt;
void foo(const A0&amp; a0, const A1&amp; a1)
{
foo_impl(foo_keywords(a0, a1));
}
</pre>
</div>
<div class="section" id="defining-the-implementation-function">
<h2><a class="toc-backref" href="#id11" name="defining-the-implementation-function">2.3   Defining the implementation function</a></h2>
<pre class="literal-block">
template&lt;class Params&gt;
void foo_impl(const Params&amp; params)
{
std::cout &lt;&lt; params[name] &lt;&lt; &quot; = &quot; &lt;&lt; params[value] &lt;&lt; &quot;\n&quot;;
}
</pre>
<p>That's it. The user calls the <tt class="literal"><span class="pre">foo()</span></tt> forwarding functions, with
either positional or named parameters. For instance:</p>
<pre class="literal-block">
foo(&quot;bar&quot;, 3.14f);
foo(value = 6.28f, &quot;baz&quot;)
</pre>
<p>Should print:</p>
<pre class="literal-block">
bar = 3.14
baz = 6.28
</pre>
<p>But we still don't have any default values, leaving any of the
parameters out results in a compilation error:</p>
<pre class="literal-block">
foo()
foo(&quot;bar&quot;)
foo(value = 3)
</pre>
<p>All fails.</p>
<p>Fortunatly, adding default values to parameters is easy:</p>
<pre class="literal-block">
template&lt;class Params&gt;
void foo_impl(const Params&amp; params)
{
std::cout
&lt;&lt; params[name | &quot;unnamed&quot;] &lt;&lt; &quot; = &quot;
&lt;&lt; params[value | 0] &lt;&lt; &quot;\n&quot;;
}
</pre>
<p>We are using <tt class="literal"><span class="pre">operator|</span></tt> to denote the default value of a named
parameter.</p>
<p>Going back a little to the <tt class="literal"><span class="pre">foo()</span></tt> call that didn't compile:</p>
<pre class="literal-block">
foo()
foo(&quot;bar&quot;)
foo(value = 3)
</pre>
<p>Now compiles, and prints:</p>
<pre class="literal-block">
unnamed = 0
bar = 0
unnamed = 3
</pre>
</div>
</div>
<div class="section" id="limitations-of-the-approach">
<h1><a class="toc-backref" href="#id12" name="limitations-of-the-approach">3   Limitations of the Approach</a></h1>
<p>Because the keywords' <tt class="literal"><span class="pre">operator=</span></tt> returns a temporary, and
temporaries cannot be bound to non-<tt class="literal"><span class="pre">const</span></tt> reference parameters,
our forwarding functions need to take their arguments by <tt class="literal"><span class="pre">const</span></tt>
reference <a class="footnote-reference" href="#forwarding" id="id2" name="id2"><sup>1</sup></a>. As a result, an argument which is bound
to a keyword with <tt class="literal"><span class="pre">operator=</span></tt> can be transparently passed by
non-const reference, but positional arguments are always passed by
<tt class="literal"><span class="pre">const</span></tt> reference unless we use the <a class="reference" href="../../bind/ref.hpp">Boost.Ref</a> library to
indicate otherwise:</p>
<pre class="literal-block">
#include &lt;boost/ref.hpp&gt;
float x;
foo(value = x); // held type is float&amp;
foo(x); // held type is float const&amp;, need help!
foo(boost::ref(x)); // held type is float&amp;
</pre>
<p>Instances of <tt class="literal"><span class="pre">boost::reference_wrapper&lt;&gt;</span></tt> generated by
<tt class="literal"><span class="pre">boost::ref</span></tt> will be unwrapped automatically by the library.</p>
</div>
<div class="section" id="controlling-overload-resolution">
<h1><a class="toc-backref" href="#id13" name="controlling-overload-resolution">4   Controlling Overload Resolution</a></h1>
<p>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 <a class="reference" href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#225">unqualified calls</a>. Probably the safest thing
to do is to isolate the forwarding functions in a namespace
containing no types <a class="footnote-reference" href="#using" id="id3" name="id3"><sup>2</sup></a>, but often we'd <em>like</em> our functions
to play nicely with argument-dependent lookup and other function
overloads. In that case, it's neccessary to somehow remove the
functions from the overload set when the passed argument types
don't meet their needs.</p>
<p>This sort of overload control can be accomplished in C++ by taking
advantage of <a class="reference" href="http://www.semantics.org/once_weakly/w02_SFINAE.pdf">SFINAE</a> (Substitution Failure Is Not An Error). 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 <tt class="literal"><span class="pre">enable_if</span></tt> utility.</p>
<p>The named parameters library provides built-in SFINAE support
through the following class template:</p>
<pre class="literal-block">
template&lt;
class KeywordTag
, class HasDefaultValue // mpl::true_ or mpl::false_
, class Predicate
&gt;
struct arg;
</pre>
<p>The key parameter, <tt class="literal"><span class="pre">Predicate</span></tt> shall be a unary MPL lambda
expression or <a class="reference" href="../../mpl/doc/ref/Metafunction_Class.html">Metafunction Class</a> that, when applied to the
actual type the argument, indicates whether that argument type
meets the function's requirements for that parameter position.</p>
<p>For example, let's say we want to restrict our <tt class="literal"><span class="pre">foo()</span></tt> so that
the <tt class="literal"><span class="pre">name</span></tt> parameter must be convertible to <tt class="literal"><span class="pre">const</span> <span class="pre">char*</span></tt>.
We'll replace our use of the <tt class="literal"><span class="pre">name_t</span></tt> tag with a specialization
of <tt class="literal"><span class="pre">boost::arg</span></tt>:</p>
<pre class="literal-block">
struct foo_keywords
: boost::keywords&lt;
<strong>boost::arg&lt;
name_t
, mpl::false_
, is_convertible&lt;mpl::_, const char*&gt;
&gt;</strong>
, value_t
&gt;
{};
</pre>
<p>Now we can add an additional optional argument to each of our
<tt class="literal"><span class="pre">foo</span></tt> overloads</p>
<pre class="literal-block">
template&lt;class A0&gt;
void foo(
const A0&amp; a0
, <strong>foo_keywords::restrict&lt;A0&gt;::type x = foo_keywords()</strong>
)
{
foo_impl(x(a0));
}
template&lt;class A0, class A1&gt;
void foo(
const A0&amp; a0, const A1&amp; a1
, <strong>foo_keywords::restrict&lt;A0,A1&gt;::type x = foo_keywords()</strong>
)
{
foo_impl(x(a0, a1));
}
</pre>
<p>These additional parameters are not intended to be used directly
by callers; they merely trigger SFINAE by becoming illegal types
when the <tt class="literal"><span class="pre">name</span></tt> argument is not convertible to <tt class="literal"><span class="pre">const</span> <span class="pre">char*</span></tt>.</p>
</div>
<div class="section" id="lazy-evaluation-of-defaults">
<h1><a class="toc-backref" href="#id14" name="lazy-evaluation-of-defaults">5   Lazy Evaluation of Defaults</a></h1>
<p>If computing an argument's default value is expensive, it's best
avoided when the argument is supplied by the user. In that case,
the default value can be lazily evaluated using the following
syntax:</p>
<pre class="literal-block">
params[keyword <strong>|| nullary_function</strong>];
</pre>
<p><tt class="literal"><span class="pre">nullary_function</span></tt> must be a function object that is callable
without arguments, and that indicates its return type via a nested
<tt class="literal"><span class="pre">result_type</span></tt>. Boost.Bind can be used to produce an appropriate
function object from a regular function pointer:</p>
<pre class="literal-block">
// expensive default computation function
float default_span(float x, float theta);
// implementation of bar()
template &lt;class Params&gt;
void bar_impl(Params const&amp; params)
{
// Extract arguments
float x_ = params[x];
float theta_ = params[theta | pi];
float span = params[span || boost::bind(default_span, x_, theta_)];
...
}
</pre>
</div>
<div class="section" id="automatic-overload-generation">
<h1><a class="toc-backref" href="#id15" name="automatic-overload-generation">6   Automatic Overload Generation</a></h1>
<p>To reduce the work needed to write functions with named parameters,
we supply a macro that generates the boilerplate code.</p>
<p>Synopsis:</p>
<pre class="literal-block">
BOOST_NAMED_PARAMS_FUN(
return_type, function_name, keywords_type
, min_arity, max_arity
);
</pre>
<p>To generate all the forwarding functions and the implementation
function for our example, we need only apply
<tt class="literal"><span class="pre">BOOST_NAMED_PARAMS_FUN</span></tt> this way:</p>
<pre class="literal-block">
BOOST_NAMED_PARAMS_FUN(void, foo, foo_keywords, 0, 2)
{
std::cout
&lt;&lt; params[name | &quot;unnamed&quot;] &lt;&lt; &quot; = &quot;
&lt;&lt; params[value | 0] &lt;&lt; &quot;\n&quot;;
}
</pre>
</div>
<div class="section" id="portability">
<h1><a class="toc-backref" href="#id16" name="portability">7   Portability</a></h1>
<p>Boost.NamedParams has been confirmed to work on the following compilers:</p>
<blockquote>
<ul class="simple">
<li>Microsoft VC6 sp5, VC7 <a class="footnote-reference" href="#norestrict" id="id5" name="id5"><sup>3</sup></a></li>
<li>Microsoft VC7.1</li>
<li>GCC3.3.1 (cygwin), GCC2.95.3 (cygwin), GCC3.2 (mingw)</li>
<li>Metrowerks Codewarrior Pro8 and Pro9 (Windows)</li>
<li>Intel C++ 5.0,6.0,7.1,8.0 (Windows)</li>
<li>Comeau 4.3.3</li>
</ul>
</blockquote>
<hr />
<table class="footnote" frame="void" id="forwarding" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id2" name="forwarding">[1]</a></td><td><p>One could provide overloads for <tt class="literal"><span class="pre">const</span></tt> and
non-<tt class="literal"><span class="pre">const</span></tt> reference versions of each parameter, but that
would quickly become unmanageable. It's known as &quot;the
forwarding problem&quot; and has been described in detail in this
<a class="reference" href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm">paper</a>. The combinatorial explosion is avoided for the
parameter of keywords' <tt class="literal"><span class="pre">operator=</span></tt> because they take only a
single argument.</p>
</td></tr>
</tbody>
</table>
<table class="footnote" frame="void" id="using" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id3" name="using">[2]</a></td><td><p>You can always give the illusion that the function
lives in an outer namespace by applying a <em>using-declaration</em>:</p>
<pre class="literal-block">
namespace foo_overloads
{
// foo declarations here
void foo() { ... }
...
}
using foo_overloads::foo;
</pre>
</td></tr>
</tbody>
</table>
<table class="footnote" frame="void" id="norestrict" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id5" name="norestrict">[3]</a></td><td>Restrictions doesn't work on these compilers because
of lack of SFINAE support.</td></tr>
</tbody>
</table>
</div>
</div>
<hr class="footer" />
<div class="footer">
<a class="reference" href="named_params.rst">View document source</a>.
Generated on: 2004-01-16 23:50 UTC.
Generated by <a class="reference" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source.
</div>
</body>
</html>