📄 index.rst
字号:
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), and it generates the appropriate defaulted
argument. 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));
} :vellipsis:`\
.
.
.
`
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:: Mnemonics
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;
}
===========
Reference
===========
.. _reference: reference.html
Follow `this link`__ to the Boost.Parameter reference
documentation.
__ reference.html
==================
Acknowledgements
==================
The authors would like to thank all the Boosters who participated
in the review of this library and its documentation, most
especially our review manager, Doug Gregor.
--------------------------
.. [#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()(A1 a1, A2 a2) { 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -