mirror of
https://github.com/boostorg/utility.git
synced 2025-08-02 22:34:31 +02:00
*** empty log message ***
[SVN r1889]
This commit is contained in:
444
doc/named_params.html
Executable file
444
doc/named_params.html
Executable 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@boost-consulting.com">dave@boost-consulting.com</a>, <a class="reference" href="mailto:dalwan01@student.umu.se">dalwan01@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("alert", 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("alert2", 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<class T> 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("alert2", 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
|
||||
"tag" types for each keyword, and declaring <tt class="literal"><span class="pre">keyword<</span></tt><em>tag</em><tt class="literal"><span class="pre">></span></tt> objects:</p>
|
||||
<pre class="literal-block">
|
||||
#include <boost/named_params.hpp>
|
||||
|
||||
struct name_t; // tag types
|
||||
struct value_t;
|
||||
|
||||
namespace {
|
||||
boost::keyword<name_t> name; // keyword objects
|
||||
boost::keyword<value_t> 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<
|
||||
name_t
|
||||
, value_t
|
||||
>
|
||||
{};
|
||||
</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<class Params>
|
||||
void foo_impl(const Params&);
|
||||
|
||||
void foo()
|
||||
{
|
||||
foo_impl(foo_keywords());
|
||||
}
|
||||
|
||||
template<class A0>
|
||||
void foo(const A0& a0)
|
||||
{
|
||||
foo_impl(foo_keywords(a0));
|
||||
}
|
||||
|
||||
template<class A0, class A1>
|
||||
void foo(const A0& a0, const A1& 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<class Params>
|
||||
void foo_impl(const Params& params)
|
||||
{
|
||||
std::cout << params[name] << " = " << params[value] << "\n";
|
||||
}
|
||||
</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("bar", 3.14f);
|
||||
foo(value = 6.28f, "baz")
|
||||
</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("bar")
|
||||
foo(value = 3)
|
||||
</pre>
|
||||
<p>All fails.</p>
|
||||
<p>Fortunatly, adding default values to parameters is easy:</p>
|
||||
<pre class="literal-block">
|
||||
template<class Params>
|
||||
void foo_impl(const Params& params)
|
||||
{
|
||||
std::cout
|
||||
<< params[name | "unnamed"] << " = "
|
||||
<< params[value | 0] << "\n";
|
||||
}
|
||||
</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("bar")
|
||||
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 <boost/ref.hpp>
|
||||
|
||||
float x;
|
||||
foo(value = x); // held type is float&
|
||||
foo(x); // held type is float const&, need help!
|
||||
foo(boost::ref(x)); // held type is float&
|
||||
</pre>
|
||||
<p>Instances of <tt class="literal"><span class="pre">boost::reference_wrapper<></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<
|
||||
class KeywordTag
|
||||
, class HasDefaultValue // mpl::true_ or mpl::false_
|
||||
, class Predicate
|
||||
>
|
||||
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<
|
||||
<strong>boost::arg<
|
||||
name_t
|
||||
, mpl::false_
|
||||
, is_convertible<mpl::_, const char*>
|
||||
></strong>
|
||||
, value_t
|
||||
>
|
||||
{};
|
||||
</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<class A0>
|
||||
void foo(
|
||||
const A0& a0
|
||||
, <strong>foo_keywords::restrict<A0>::type x = foo_keywords()</strong>
|
||||
)
|
||||
{
|
||||
foo_impl(x(a0));
|
||||
}
|
||||
|
||||
template<class A0, class A1>
|
||||
void foo(
|
||||
const A0& a0, const A1& a1
|
||||
, <strong>foo_keywords::restrict<A0,A1>::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 <class Params>
|
||||
void bar_impl(Params const& 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
|
||||
<< params[name | "unnamed"] << " = "
|
||||
<< params[value | 0] << "\n";
|
||||
}
|
||||
</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 "the
|
||||
forwarding problem" 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>
|
Reference in New Issue
Block a user