2924 lines
88 KiB
ReStructuredText
2924 lines
88 KiB
ReStructuredText
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
The Boost Parameter Library
|
||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
|(logo)|__
|
||
|
||
.. |(logo)| image:: ../../../../boost.png
|
||
:alt: Boost
|
||
|
||
__ ../../../../index.htm
|
||
|
||
-------------------------------------
|
||
|
||
:Abstract: Use this library to write functions and class templates that can
|
||
accept arguments by name:
|
||
|
||
.. parsed-literal::
|
||
|
||
new_window(
|
||
"alert"
|
||
, **_width=10**
|
||
, **_titlebar=false**
|
||
);
|
||
|
||
smart_ptr<
|
||
Foo
|
||
, **deleter<Deallocate<Foo> >**
|
||
, **copy_policy<DeepCopy>**
|
||
> p(new Foo);
|
||
|
||
Since named arguments can be passed in any order, they are especially useful
|
||
when a function or template has more than one parameter with a useful default
|
||
value. The library also supports *deduced* parameters: that is to say,
|
||
parameters whose identity can be deduced from their types.
|
||
|
||
.. @jam_prefix.append('''
|
||
project test
|
||
: requirements <include>. <implicit-dependency>/boost//headers ;
|
||
''')
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
|
||
namespace test {
|
||
|
||
BOOST_PARAMETER_NAME(title)
|
||
BOOST_PARAMETER_NAME(width)
|
||
BOOST_PARAMETER_NAME(titlebar)
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(int), new_window, tag, (required (title,*)(width,*)(titlebar,*))
|
||
)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(deleter)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(copy_policy)
|
||
|
||
template <typename T>
|
||
struct Deallocate
|
||
{
|
||
};
|
||
|
||
struct DeepCopy
|
||
{
|
||
};
|
||
|
||
namespace parameter = boost::parameter;
|
||
|
||
struct Foo
|
||
{
|
||
};
|
||
|
||
template <typename T, typename A0, typename A1>
|
||
struct smart_ptr
|
||
{
|
||
smart_ptr(Foo*);
|
||
};
|
||
}
|
||
using namespace test;
|
||
int x =
|
||
''');
|
||
|
||
.. @test('compile')
|
||
|
||
|
||
-------------------------------------
|
||
|
||
:Authors: David Abrahams, Daniel Wallin
|
||
:Contact: dave@boost-consulting.com, daniel@boostpro.com
|
||
:organization: `BoostPro Computing`_
|
||
:date: $Date: 2005/07/17 19:53:01 $
|
||
|
||
:copyright: Copyright David Abrahams, Daniel Wallin
|
||
2005-2009. 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)
|
||
|
||
.. _`BoostPro Computing`: http://www.boostpro.com
|
||
|
||
.. _concepts: http://www.boost.org/more/generic_programming.html#concept
|
||
|
||
-------------------------------------
|
||
|
||
[Note: this tutorial does not cover all details of the library. Please see
|
||
also the `reference documentation`__\ ]
|
||
|
||
__ reference.html
|
||
|
||
.. contents:: **Table of Contents**
|
||
:depth: 2
|
||
|
||
.. role:: concept
|
||
:class: concept
|
||
|
||
.. role:: vellipsis
|
||
:class: vellipsis
|
||
|
||
.. section-numbering::
|
||
|
||
-------------------------------------
|
||
|
||
==========
|
||
Motivation
|
||
==========
|
||
|
||
In C++, arguments_ are normally given meaning by their positions with respect
|
||
to a parameter_ list: the first argument passed maps onto the first parameter
|
||
in a function's definition, and so on. 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:
|
||
|
||
* .. compound::
|
||
|
||
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
|
||
);
|
||
|
||
bool const 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
|
||
);
|
||
|
||
* .. compound::
|
||
|
||
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.
|
||
|
||
.. @ignore(3)
|
||
|
||
-------------------------
|
||
Named Function Parameters
|
||
-------------------------
|
||
|
||
.. compound::
|
||
|
||
This library addresses the problems outlined above by associating each
|
||
parameter name with a keyword object. Now users can identify arguments by
|
||
name, rather than by position:
|
||
|
||
.. parsed-literal::
|
||
|
||
window* w = new_window(
|
||
"alert box"
|
||
, **movable_=**\ false
|
||
); // OK!
|
||
|
||
.. @ignore()
|
||
|
||
---------------------------
|
||
Deduced Function Parameters
|
||
---------------------------
|
||
|
||
.. compound::
|
||
|
||
A **deduced parameter** can be passed in any position *without* supplying
|
||
an explicit parameter name. It's not uncommon for a function to have
|
||
parameters that can be uniquely identified based on the types of arguments
|
||
passed. The ``name`` parameter to ``new_window`` is one such
|
||
example. None of the other arguments, if valid, can reasonably be
|
||
converted to a ``char const*``. With a deduced parameter interface, we
|
||
could pass the window name in *any* argument position without causing
|
||
ambiguity:
|
||
|
||
.. parsed-literal::
|
||
|
||
window* w = new_window(
|
||
movable_=false
|
||
, **"alert box"**
|
||
); // OK!
|
||
window* w = new_window(
|
||
**"alert box"**
|
||
, movable_=false
|
||
); // OK!
|
||
|
||
Appropriately used, a deduced parameter interface can free the user of the
|
||
burden of even remembering the formal parameter names.
|
||
|
||
.. @ignore()
|
||
|
||
--------------------------------
|
||
Class Template Parameter Support
|
||
--------------------------------
|
||
|
||
.. compound::
|
||
|
||
The reasoning we've given for named and deduced parameter interfaces
|
||
applies equally well to class templates as it does to functions. Using
|
||
the Parameter library, we can create interfaces that allow template
|
||
arguments (in this case ``shared`` and ``Client``) to be explicitly named,
|
||
like this:
|
||
|
||
.. parsed-literal::
|
||
|
||
smart_ptr<
|
||
**ownership<shared>**
|
||
, **value_type<Client>**
|
||
> p;
|
||
|
||
The syntax for passing named template arguments is not quite as natural as
|
||
it is for function arguments (ideally, we'd be able to write
|
||
``smart_ptr<ownership = shared, …>``). This small syntactic deficiency
|
||
makes deduced parameters an especially big win when used with class
|
||
templates:
|
||
|
||
.. parsed-literal::
|
||
|
||
// *p and q could be equivalent, given a deduced*
|
||
// *parameter interface.*
|
||
smart_ptr<**shared**, **Client**> p;
|
||
smart_ptr<**Client**, **shared**> q;
|
||
|
||
.. @ignore(2)
|
||
|
||
========
|
||
Tutorial
|
||
========
|
||
|
||
This tutorial shows all the basics—how to build both named- and
|
||
deduced-parameter interfaces to function templates and class
|
||
templates—and several more advanced idioms as well.
|
||
|
||
---------------------------
|
||
Parameter-Enabled Functions
|
||
---------------------------
|
||
|
||
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]_
|
||
|
||
.. Revisit this
|
||
|
||
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/doc/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.
|
||
|
||
.. @example.append('''
|
||
using boost::parameter::keyword;
|
||
''')
|
||
|
||
.. @test('compile')
|
||
|
||
Also, the examples below will also be written as if the namespace alias ::
|
||
|
||
namespace parameter = boost::parameter;
|
||
|
||
.. @ignore()
|
||
|
||
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. If all arguments were
|
||
required, its signature might be as follows::
|
||
|
||
template <
|
||
typename Graph
|
||
, typename DFSVisitor
|
||
, typename Index
|
||
, typename ColorMap
|
||
>
|
||
void
|
||
depth_first_search(
|
||
Graph const& graph
|
||
, DFSVisitor visitor
|
||
, typename graph_traits<g>::vertex_descriptor root_vertex
|
||
, IndexMap index_map
|
||
, ColorMap& color
|
||
);
|
||
|
||
.. @ignore()
|
||
|
||
However, most of the parameters have a useful default value,
|
||
as shown in the table below.
|
||
|
||
.. _`parameter table`:
|
||
.. _`default expressions`:
|
||
|
||
.. table:: ``depth_first_search`` Parameters
|
||
|
||
+-----------------+------+-------------------------+------------------------------------+
|
||
| Parameter | Data | Type | Default Value |
|
||
| Name | Flow | | (if any) |
|
||
+=================+======+=========================+====================================+
|
||
| ``graph`` | in | Model of | none - this argument is required. |
|
||
| | | |IncidenceGraph|_ and | |
|
||
| | | |VertexListGraph|_ | |
|
||
+-----------------+------+-------------------------+------------------------------------+
|
||
| ``visitor`` | in | Model of |DFSVisitor|_ | ``boost::dfs_visitor<>()`` |
|
||
+-----------------+------+-------------------------+------------------------------------+
|
||
| ``root_vertex`` | in | ``graph``'s vertex | ``*vertices(graph).first`` |
|
||
| | | descriptor type. | |
|
||
+-----------------+------+-------------------------+------------------------------------+
|
||
| ``index_map`` | in | Model of | ``get(boost::vertex_index,graph)`` |
|
||
| | | |ReadablePropertyMap|_ | |
|
||
| | | with key type := | |
|
||
| | | ``graph``'s vertex | |
|
||
| | | descriptor and value | |
|
||
| | | type an integer type. | |
|
||
+-----------------+------+-------------------------+------------------------------------+
|
||
| ``color_map`` | in / | Model of | a ``boost::iterator_property_map`` |
|
||
| | out | |ReadWritePropertyMap|_ | created from a ``std::vector`` of |
|
||
| | | with key type := | ``default_color_type`` of size |
|
||
| | | ``graph``'s vertex | ``num_vertices(graph)`` and using |
|
||
| | | descriptor type. | ``index_map`` for the index map. |
|
||
+-----------------+------+-------------------------+------------------------------------+
|
||
|
||
.. |IncidenceGraph| replace:: :concept:`Incidence Graph`
|
||
.. |VertexListGraph| replace:: :concept:`Vertex List Graph`
|
||
.. |DFSVisitor| replace:: :concept:`DFS Visitor`
|
||
.. |ReadablePropertyMap| replace:: :concept:`Readable Property Map`
|
||
.. |ReadWritePropertyMap| replace:: :concept:`Read/Write Property Map`
|
||
|
||
.. _`IncidenceGraph`: ../../../graph/doc/IncidenceGraph.html
|
||
.. _`VertexListGraph`: ../../../graph/doc/VertexListGraph.html
|
||
.. _`DFSVisitor`: ../../../graph/doc/DFSVisitor.html
|
||
.. _`ReadWritePropertyMap`: ../../../property_map/doc/ReadWritePropertyMap.html
|
||
.. _`ReadablePropertyMap`: ../../../property_map/doc/ReadablePropertyMap.html
|
||
|
||
Don't be intimidated by the information in the second and third columns
|
||
above. For the purposes of this exercise, you don't need to understand
|
||
them in detail.
|
||
|
||
Defining the Keywords
|
||
=====================
|
||
|
||
The point of this exercise is to make it possible to call
|
||
``depth_first_search`` with named arguments, leaving out any
|
||
arguments for which the default is appropriate:
|
||
|
||
.. parsed-literal::
|
||
|
||
graphs::depth_first_search(g, **color_map_=my_color_map**);
|
||
|
||
.. @ignore()
|
||
|
||
To make that syntax legal, there needs to be an object called
|
||
“\ ``color_map_``\ ” whose assignment operator 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**.
|
||
|
||
.. Revisit this
|
||
|
||
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 accessible through ``graphs``, and we'll
|
||
hide the tag types away in a nested namespace, ``graphs::tag``. The
|
||
library provides a convenient macro for that purpose.
|
||
|
||
We're going to define our interface in namespace ``graphs``. The
|
||
library provides a convenient macro for defining keyword objects::
|
||
|
||
#include <boost/parameter/name.hpp>
|
||
|
||
namespace graphs {
|
||
|
||
BOOST_PARAMETER_NAME(graph) // Note: no semicolon
|
||
BOOST_PARAMETER_NAME(visitor)
|
||
BOOST_PARAMETER_NAME(root_vertex)
|
||
BOOST_PARAMETER_NAME(index_map)
|
||
BOOST_PARAMETER_NAME(color_map)
|
||
}
|
||
|
||
.. @test('compile')
|
||
|
||
The declaration of the ``graph`` keyword you see here is equivalent to::
|
||
|
||
namespace graphs {
|
||
namespace tag {
|
||
|
||
// keyword tag type
|
||
struct graph
|
||
{
|
||
typedef boost::parameter::forward_reference qualifier;
|
||
};
|
||
}
|
||
|
||
namespace // unnamed
|
||
{
|
||
// A reference to the keyword object
|
||
boost::parameter::keyword<tag::graph> const& _graph
|
||
= boost::parameter::keyword<tag::graph>::instance;
|
||
}
|
||
}
|
||
|
||
.. @example.prepend('#include <boost/parameter/keyword.hpp>')
|
||
.. @test('compile')
|
||
|
||
It defines a *keyword tag type* named ``tag::graph`` and a *keyword object*
|
||
reference named ``_graph``.
|
||
|
||
This “fancy dance” involving an 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 (MSVC6.x users see `this note`__).
|
||
|
||
__ `Compiler Can't See References In Unnamed Namespace`_
|
||
|
||
Writing the Function
|
||
====================
|
||
|
||
Now that we have our keywords defined, the function template definition
|
||
follows a simple pattern using the ``BOOST_PARAMETER_FUNCTION`` macro::
|
||
|
||
#include <boost/parameter/preprocessor.hpp>
|
||
|
||
namespace graphs {
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(void), // 1. parenthesized return type
|
||
depth_first_search, // 2. name of the function template
|
||
tag, // 3. namespace of tag types
|
||
(required (graph, *) ) // 4. one required parameter, and
|
||
(optional // four optional parameters,
|
||
// with defaults
|
||
(visitor, *, boost::dfs_visitor<>())
|
||
(root_vertex, *, *vertices(graph).first)
|
||
(index_map, *, get(boost::vertex_index,graph))
|
||
(color_map, *,
|
||
default_color_map(num_vertices(graph), index_map)
|
||
)
|
||
)
|
||
)
|
||
{
|
||
// ... body of function goes here...
|
||
// use graph, visitor, index_map, and color_map
|
||
}
|
||
}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter/name.hpp>
|
||
|
||
BOOST_PARAMETER_NAME(graph)
|
||
BOOST_PARAMETER_NAME(visitor)
|
||
BOOST_PARAMETER_NAME(in(root_vertex))
|
||
BOOST_PARAMETER_NAME(in(index_map))
|
||
BOOST_PARAMETER_NAME(in_out(color_map))
|
||
|
||
namespace boost {
|
||
|
||
template <typename T = int>
|
||
struct dfs_visitor
|
||
{
|
||
};
|
||
|
||
int vertex_index = 0;
|
||
}
|
||
''')
|
||
|
||
.. @test('compile')
|
||
|
||
The arguments to ``BOOST_PARAMETER_FUNCTION`` are:
|
||
|
||
1. The return type of the resulting function template. Parentheses around
|
||
the return type prevent any commas it might contain from confusing the
|
||
preprocessor, and are always required.
|
||
|
||
2. The name of the resulting function template.
|
||
|
||
3. The name of a namespace where we can find tag types whose names match the
|
||
function's parameter names.
|
||
|
||
4. The function signature.
|
||
|
||
Function Signatures
|
||
===================
|
||
|
||
Function signatures are described as one or two adjacent parenthesized terms
|
||
(a Boost.Preprocessor_ sequence_) describing the function's parameters in the
|
||
order in which they'd be expected if passed positionally. Any required
|
||
parameters must come first, but the ``(required … )`` clause can be omitted
|
||
when all the parameters are optional.
|
||
|
||
.. _Boost.Preprocessor: ../../../preprocessor/doc/index.html
|
||
.. _sequence: http://boost-consulting.com/mplbook/preprocessor.html#sequences
|
||
|
||
Required Parameters
|
||
-------------------
|
||
|
||
.. compound::
|
||
|
||
Required parameters are given first—nested in a ``(required … )``
|
||
clause—as a series of two-element tuples describing each parameter name
|
||
and any requirements on the argument type. In this case there is only a
|
||
single required parameter, so there's just a single tuple:
|
||
|
||
.. parsed-literal::
|
||
|
||
(required **(graph, \*)** )
|
||
|
||
Since ``depth_first_search`` doesn't require any particular type for its
|
||
``graph`` parameter, we use an asterix to indicate that any type is
|
||
allowed. Required parameters must always precede any optional parameters
|
||
in a signature, but if there are *no* required parameters, the
|
||
``(required … )`` clause can be omitted entirely.
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
|
||
BOOST_PARAMETER_NAME(graph)
|
||
|
||
BOOST_PARAMETER_FUNCTION((void), f, tag,
|
||
''')
|
||
|
||
.. @example.append(') {}')
|
||
.. @test('compile')
|
||
|
||
Optional Parameters
|
||
-------------------
|
||
|
||
.. compound::
|
||
|
||
Optional parameters—nested in an ``(optional … )`` clause—are given as a
|
||
series of adjacent *three*\ -element tuples describing the parameter name,
|
||
any requirements on the argument type, *and* and an expression
|
||
representing the parameter's default value:
|
||
|
||
.. parsed-literal::
|
||
|
||
(optional
|
||
**(visitor, \*, boost::dfs_visitor<>())
|
||
(root_vertex, \*, \*vertices(graph).first)
|
||
(index_map, \*, get(boost::vertex_index,graph))
|
||
(color_map, \*,
|
||
default_color_map(num_vertices(graph), index_map)
|
||
)**
|
||
)
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
|
||
namespace boost {
|
||
|
||
int vertex_index = 0;
|
||
|
||
template <typename T = int>
|
||
struct dfs_visitor
|
||
{
|
||
};
|
||
}
|
||
|
||
BOOST_PARAMETER_NAME(graph)
|
||
BOOST_PARAMETER_NAME(visitor)
|
||
BOOST_PARAMETER_NAME(in(root_vertex))
|
||
BOOST_PARAMETER_NAME(in(index_map))
|
||
BOOST_PARAMETER_NAME(in_out(color_map))
|
||
|
||
BOOST_PARAMETER_FUNCTION((void), f, tag,
|
||
(required (graph, \*))
|
||
''')
|
||
|
||
.. @example.append(') {}')
|
||
.. @test('compile')
|
||
|
||
Handling “In”, “Out”, “Consume / Move-From”, and “Forward” Parameters
|
||
---------------------------------------------------------------------
|
||
|
||
.. compound::
|
||
|
||
By default, Boost.Parameter treats all parameters as if they were
|
||
*forward* `parameters`_, which functions would take in by rvalue reference
|
||
and only ``std::forward`` or ``boost::forward`` to other functions. Such
|
||
parameters can be ``const`` lvalues, mutable lvalues, ``const`` rvalues,
|
||
or mutable rvalues. Therefore, the default configuration grants the most
|
||
flexibility to user code. However:
|
||
|
||
* Users can configure one or more parameters to be *in* `parameters`_,
|
||
which can fall into the same categories as *forward* `parameters`_ but
|
||
are now passed by ``const`` lvalue reference and so must only be read
|
||
from. Continuing from the previous example, to indicate that
|
||
``root_vertex`` and ``index_map`` are read-only, we wrap their names
|
||
in ``in(…)``.
|
||
|
||
* Users can configure one or more parameters to be either *out*
|
||
`parameters`_, which functions would strictly write to, or *in-out*
|
||
`parameters`_, which functions would both read from and write
|
||
to. Such parameters can only be mutable lvalues. In the example, to
|
||
indicate that ``color_map`` is read-write, we wrap its name in
|
||
``in_out(…)``. Note that Boost.Parameter sees no functional
|
||
difference between ``out(…)`` and ``in_out(…)``, so you may choose
|
||
whichever makes your interfaces more self-documenting.
|
||
|
||
* Users can configure one or more parameters to be *consume* or
|
||
*move-from* `parameters`_, which functions would take in by mutable
|
||
rvalue reference and ``std::move`` or ``boost::move`` as the last
|
||
access step. Such parameters can only be mutable
|
||
rvalues. Boost.Parameter supports wrapping the corresponding names in
|
||
``consume(…)`` or ``move_from(…)``.
|
||
|
||
.. parsed-literal::
|
||
|
||
BOOST_PARAMETER_NAME(graph)
|
||
BOOST_PARAMETER_NAME(visitor)
|
||
BOOST_PARAMETER_NAME(**in(root_vertex)**)
|
||
BOOST_PARAMETER_NAME(**in(index_map)**)
|
||
BOOST_PARAMETER_NAME(**in_out(color_map)**)
|
||
|
||
In order to see what happens when parameters are bound to arguments that
|
||
violate their category constraints, attempt to compile the |compose_cpp|_
|
||
test program with either the ``LIBS_PARAMETER_TEST_COMPILE_FAILURE_0``
|
||
macro or the ``LIBS_PARAMETER_TEST_COMPILE_FAILURE_1`` macro
|
||
``#defined``. You should encounter a compiler error caused by a specific
|
||
constraint violation.
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
|
||
namespace boost {
|
||
|
||
int vertex_index = 0;
|
||
|
||
template <typename T = int>
|
||
struct dfs_visitor
|
||
{
|
||
};
|
||
}
|
||
''')
|
||
|
||
.. @example.append('''
|
||
BOOST_PARAMETER_FUNCTION((void), f, tag,
|
||
(required (graph, \*))
|
||
(optional
|
||
(visitor, \*, boost::dfs_visitor<>())
|
||
(root_vertex, \*, \*vertices(graph).first)
|
||
(index_map, \*, get(boost::vertex_index, graph))
|
||
(color_map, \*,
|
||
default_color_map(num_vertices(graph), index_map)
|
||
)
|
||
)
|
||
)
|
||
{
|
||
}
|
||
''')
|
||
|
||
.. @test('compile')
|
||
|
||
.. _`parameters`: http://www.modernescpp.com/index.php/c-core-guidelines-how-to-pass-function-parameters
|
||
.. |compose_cpp| replace:: compose.cpp
|
||
.. _compose_cpp: ../../test/compose.cpp
|
||
|
||
Positional Arguments
|
||
--------------------
|
||
|
||
When arguments are passed positionally (without the use of keywords), they
|
||
will be mapped onto parameters in the order the parameters are given in the
|
||
signature, so for example in this call ::
|
||
|
||
graphs::depth_first_search(x, y);
|
||
|
||
.. @ignore()
|
||
|
||
``x`` will always be interpreted as a graph and ``y`` will always be
|
||
interpreted as a visitor.
|
||
|
||
Default Expression Evaluation
|
||
-----------------------------
|
||
|
||
.. compound::
|
||
|
||
Note that in our example, the value of the graph parameter is used in the
|
||
default expressions for ``root_vertex``, ``index_map``, and ``color_map``.
|
||
|
||
.. parsed-literal::
|
||
|
||
(required (**graph**, \*) )
|
||
(optional
|
||
(visitor, \*, boost::dfs_visitor<>())
|
||
(root_vertex, \*, \*vertices(**graph**).first)
|
||
(index_map, \*, get(boost::vertex_index, **graph**))
|
||
(color_map, \*,
|
||
default_color_map(num_vertices(**graph**), index_map)
|
||
)
|
||
)
|
||
|
||
.. @ignore()
|
||
|
||
A default expression is evaluated in the context of all preceding
|
||
parameters, so you can use any of their values by name.
|
||
|
||
.. compound::
|
||
|
||
A default expression is never evaluated—or even instantiated—if an actual
|
||
argument is passed for that parameter. We can actually demonstrate that
|
||
with our code so far by replacing the body of ``depth_first_search`` with
|
||
something that prints the arguments:
|
||
|
||
.. parsed-literal::
|
||
|
||
#include <boost/graph/depth_first_search.hpp> // for dfs_visitor
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(bool), depth_first_search, tag
|
||
*…signature goes here…*
|
||
)
|
||
{
|
||
std::cout << "graph=" << graph;
|
||
std::cout << std::endl;
|
||
std::cout << "visitor=" << visitor;
|
||
std::cout << std::endl;
|
||
std::cout << "root_vertex=" << root_vertex;
|
||
std::cout << std::endl;
|
||
std::cout << "index_map=" << index_map;
|
||
std::cout << std::endl;
|
||
std::cout << "color_map=" << color_map;
|
||
std::cout << std::endl;
|
||
return true;
|
||
}
|
||
|
||
#include <boost/core/lightweight_test.hpp>
|
||
|
||
int main()
|
||
{
|
||
char const\* g = "1";
|
||
depth_first_search(1, 2, 3, 4, 5);
|
||
depth_first_search(
|
||
g, '2', _color_map = '5',
|
||
_index_map = "4", _root_vertex = "3"
|
||
);
|
||
return boost::report_errors();
|
||
}
|
||
|
||
Despite the fact that default expressions such as
|
||
``vertices(graph).first`` are ill-formed for the given ``graph``
|
||
arguments, both calls will compile, and each one will print exactly the
|
||
same thing.
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <iostream>
|
||
|
||
BOOST_PARAMETER_NAME(graph)
|
||
BOOST_PARAMETER_NAME(visitor)
|
||
BOOST_PARAMETER_NAME(root_vertex)
|
||
BOOST_PARAMETER_NAME(index_map)
|
||
BOOST_PARAMETER_NAME(color_map)
|
||
''')
|
||
|
||
.. @example.replace_emphasis('''
|
||
, (required
|
||
(graph, \*)
|
||
(visitor, \*)
|
||
(root_vertex, \*)
|
||
(index_map, \*)
|
||
(color_map, \*)
|
||
)
|
||
''')
|
||
.. @test('run')
|
||
|
||
Signature Matching and Overloading
|
||
----------------------------------
|
||
|
||
In fact, the function signature is so general that any call to
|
||
``depth_first_search`` with fewer than five arguments will match our function,
|
||
provided we pass *something* for the required ``graph`` parameter. That might
|
||
not seem to be a problem at first; after all, if the arguments don't match the
|
||
requirements imposed by the implementation of ``depth_first_search``, a
|
||
compilation error will occur later, when its body is instantiated.
|
||
|
||
There are at least three problems with very general function signatures.
|
||
|
||
1. By the time our ``depth_first_search`` is instantiated, it has been
|
||
selected as the best matching overload. Some other ``depth_first_search``
|
||
overload might've worked had it been chosen instead. By the time we see a
|
||
compilation error, there's no chance to change that decision.
|
||
|
||
2. Even if there are no overloads, error messages generated at instantiation
|
||
time usually expose users to confusing implementation details. For
|
||
example, users might see references to names generated by
|
||
``BOOST_PARAMETER_FUNCTION`` such as
|
||
``graphs::detail::depth_first_search_with_named_params`` (or worse—think
|
||
of the kinds of errors you get from your STL implementation when you make
|
||
a mistake). [#ConceptsTS]_
|
||
|
||
3. The problems with exposing such permissive function template signatures
|
||
have been the subject of much discussion, especially in the presence of
|
||
`unqualified calls`__. If all we want is to avoid unintentional
|
||
argument-dependent lookup (ADL), we can isolate ``depth_first_search`` in
|
||
a namespace containing no types [#using]_, but suppose we *want* it to
|
||
found via ADL?
|
||
|
||
__ http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#225
|
||
|
||
It's usually a good idea to prevent functions from being considered for
|
||
overload resolution when the passed argument types aren't appropriate. The
|
||
library already does this when the required ``graph`` parameter is not
|
||
supplied, but we're not likely to see a depth first search that doesn't take a
|
||
graph to operate on. Suppose, instead, that we found a different depth first
|
||
search algorithm that could work on graphs that don't model
|
||
|IncidenceGraph|_? If we just added a simple overload, it would be
|
||
ambiguous::
|
||
|
||
// new overload
|
||
BOOST_PARAMETER_FUNCTION((void), depth_first_search, (tag),
|
||
(required (graph,*))( … )
|
||
)
|
||
{
|
||
// new algorithm implementation
|
||
}
|
||
|
||
…
|
||
|
||
// ambiguous!
|
||
depth_first_search(boost::adjacency_list<>(), 2, "hello");
|
||
|
||
.. @ignore()
|
||
|
||
Predicate Requirements
|
||
......................
|
||
|
||
We really don't want the compiler to consider the original version of
|
||
``depth_first_search`` because the ``root_vertex`` argument, ``"hello"``,
|
||
doesn't meet the requirement__ that it match the ``graph`` parameter's vertex
|
||
descriptor type. Instead, this call should just invoke our new overload. To
|
||
take the original ``depth_first_search`` overload out of contention, we first
|
||
encode this requirement as follows:
|
||
|
||
__ `parameter table`_
|
||
|
||
.. parsed-literal::
|
||
|
||
struct vertex_descriptor_predicate
|
||
{
|
||
template <typename T, typename Args>
|
||
struct apply
|
||
: boost::mpl::if_<
|
||
boost::is_convertible<
|
||
T
|
||
, typename boost::graph_traits<
|
||
typename boost::parameter::value_type<
|
||
Args
|
||
, graphs::graph
|
||
>::type
|
||
>::vertex_descriptor
|
||
>
|
||
, boost::mpl::true\_
|
||
, boost::mpl::false\_
|
||
>
|
||
{
|
||
};
|
||
};
|
||
|
||
This encoding is an `MPL Binary Metafunction Class`__, a type with a nested
|
||
``apply`` metafunction that takes in two template arguments. For the first
|
||
template argument, Boost.Parameter will pass in the type on which we will
|
||
impose the requirement. For the second template argument, Boost.Parameter
|
||
will pass in the entire argument pack, making it possible to extract the
|
||
type of each of the other ``depth_first_search`` parameters via the
|
||
``value_type`` metafunction and the corresponding keyword tag type. The
|
||
result ``type`` of the ``apply`` metafunction will be equivalent to
|
||
``boost::mpl::true_`` if ``T`` fulfills our requirement as imposed by the
|
||
``boost::is_convertible`` statement; otherwise, the result will be
|
||
equivalent to ``boost::mpl::false_``.
|
||
|
||
__ ../../../mpl/doc/refmanual/metafunction-class.html
|
||
|
||
At this point, we can append the name of our metafunction class, in
|
||
parentheses, to the appropriate ``*`` element of the function signature.
|
||
|
||
.. parsed-literal::
|
||
|
||
(root_vertex
|
||
, \*(**vertex_descriptor_predicate**)
|
||
, \*vertices(graph).first
|
||
)
|
||
|
||
.. @ignore()
|
||
|
||
Now the original ``depth_first_search`` will only be called when the
|
||
``root_vertex`` argument can be converted to the graph's vertex descriptor
|
||
type, and our example that *was* ambiguous will smoothly call the new
|
||
overload.
|
||
|
||
We can encode the requirements on other arguments using the same concept; only
|
||
the implementation of the nested ``apply`` metafunction needs to be tweaked
|
||
for each argument. There's no space to give a complete description of graph
|
||
library details here, but suffice it to show that the next few metafunction
|
||
classes provide the necessary checks.
|
||
|
||
.. parsed-literal::
|
||
|
||
struct graph_predicate
|
||
{
|
||
template <typename T, typename Args>
|
||
struct apply
|
||
: boost::mpl::eval_if<
|
||
boost::is_convertible<
|
||
typename boost::graph_traits<T>::traversal_category
|
||
, boost::incidence_graph_tag
|
||
>
|
||
, boost::mpl::if_<
|
||
boost::is_convertible<
|
||
typename boost::graph_traits<T>::traversal_category
|
||
, boost::vertex_list_graph_tag
|
||
>
|
||
, boost::mpl::true\_
|
||
, boost::mpl::false\_
|
||
>
|
||
>
|
||
{
|
||
};
|
||
};
|
||
|
||
struct index_map_predicate
|
||
{
|
||
template <typename T, typename Args>
|
||
struct apply
|
||
: boost::mpl::eval_if<
|
||
boost::is_integral<
|
||
typename boost::property_traits<T>::value_type
|
||
>
|
||
, boost::mpl::if_<
|
||
boost::is_same<
|
||
typename boost::property_traits<T>::key_type
|
||
, typename boost::graph_traits<
|
||
typename boost::parameter::value_type<
|
||
Args
|
||
, graphs::graph
|
||
>::type
|
||
>::vertex_descriptor
|
||
>
|
||
, boost::mpl::true\_
|
||
, boost::mpl::false\_
|
||
>
|
||
>
|
||
{
|
||
};
|
||
};
|
||
|
||
struct color_map_predicate
|
||
{
|
||
template <typename T, typename Args>
|
||
struct apply
|
||
: boost::mpl::if_<
|
||
boost::is_same<
|
||
typename boost::property_traits<T>::key_type
|
||
, typename boost::graph_traits<
|
||
typename boost::parameter::value_type<
|
||
Args
|
||
, graphs::graph
|
||
>::type
|
||
>::vertex_descriptor
|
||
>
|
||
, boost::mpl::true\_
|
||
, boost::mpl::false\_
|
||
>
|
||
{
|
||
};
|
||
};
|
||
|
||
Likewise, computing the default value for the ``color_map`` parameter is no
|
||
trivial matter, so it's best to factor the computation out to a separate
|
||
function template.
|
||
|
||
.. parsed-literal::
|
||
|
||
template <typename Size, typename IndexMap>
|
||
boost::iterator_property_map<
|
||
std::vector<boost::default_color_type>::iterator
|
||
, IndexMap
|
||
, boost::default_color_type
|
||
, boost::default_color_type&
|
||
>&
|
||
default_color_map(Size num_vertices, IndexMap const& index_map)
|
||
{
|
||
static std::vector<boost::default_color_type> colors(num_vertices);
|
||
static boost::iterator_property_map<
|
||
std::vector<boost::default_color_type>::iterator
|
||
, IndexMap
|
||
, boost::default_color_type
|
||
, boost::default_color_type&
|
||
> m(colors.begin(), index_map);
|
||
return m;
|
||
}
|
||
|
||
The signature encloses each predicate metafunction in parentheses *preceded
|
||
by an asterix*, as follows:
|
||
|
||
.. parsed-literal::
|
||
|
||
BOOST_PARAMETER_FUNCTION((void), depth_first_search, graphs,
|
||
(required
|
||
(graph, \*(**graph_predicate**))
|
||
)
|
||
(optional
|
||
(visitor
|
||
, \* // not easily checkable
|
||
, boost::dfs_visitor<>()
|
||
)
|
||
(root_vertex
|
||
, (**vertex_descriptor_predicate**)
|
||
, \*vertices(graph).first
|
||
)
|
||
(index_map
|
||
, \*(**index_map_predicate**)
|
||
, get(boost::vertex_index, graph)
|
||
)
|
||
(color_map
|
||
, \*(**color_map_predicate**)
|
||
, default_color_map(num_vertices(graph), index_map)
|
||
)
|
||
)
|
||
)
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <boost/graph/adjacency_list.hpp>
|
||
#include <boost/graph/depth_first_search.hpp>
|
||
#include <boost/graph/graph_traits.hpp>
|
||
#include <boost/property_map/property_map.hpp>
|
||
#include <boost/mpl/and.hpp>
|
||
#include <boost/type_traits/is_convertible.hpp>
|
||
#include <boost/type_traits/is_integral.hpp>
|
||
#include <boost/type_traits/is_same.hpp>
|
||
#include <vector>
|
||
#include <utility>
|
||
|
||
BOOST_PARAMETER_NAME((_graph, graphs) graph)
|
||
BOOST_PARAMETER_NAME((_visitor, graphs) visitor)
|
||
BOOST_PARAMETER_NAME((_root_vertex, graphs) in(root_vertex))
|
||
BOOST_PARAMETER_NAME((_index_map, graphs) in(index_map))
|
||
BOOST_PARAMETER_NAME((_color_map, graphs) in_out(color_map))
|
||
''')
|
||
|
||
.. @example.append('''
|
||
{
|
||
}
|
||
|
||
#include <boost/core/lightweight_test.hpp>
|
||
#include <boost/graph/adjacency_list.hpp>
|
||
#include <utility>
|
||
|
||
int main()
|
||
{
|
||
typedef boost::adjacency_list<
|
||
boost::vecS, boost::vecS, boost::directedS
|
||
> G;
|
||
enum {u, v, w, x, y, z, N};
|
||
typedef std::pair<int, int> E;
|
||
E edges[] = {
|
||
E(u, v), E(u, x), E(x, v), E(y, x),
|
||
E(v, y), E(w, y), E(w,z), E(z, z)
|
||
};
|
||
G g(edges, edges + sizeof(edges) / sizeof(E), N);
|
||
|
||
depth_first_search(g);
|
||
depth_first_search(g, _root_vertex = static_cast<int>(x));
|
||
return boost::report_errors();
|
||
}
|
||
''')
|
||
|
||
.. @test('run')
|
||
|
||
It usually isn't necessary to so completely encode the type requirements on
|
||
arguments to generic functions. However, doing so is worth the effort: your
|
||
code will be more self-documenting and will often provide a better user
|
||
experience. You'll also have an easier transition to the C++20 standard with
|
||
`language support for constraints and concepts`__.
|
||
|
||
__ `ConceptsTS`_
|
||
|
||
More on Type Requirements
|
||
.........................
|
||
|
||
Encoding type requirements onto a function's parameters is essential for
|
||
enabling the function to have deduced parameter interface. Let's revisit the
|
||
``new_window`` example for a moment:
|
||
|
||
.. parsed-literal::
|
||
|
||
window\* w = new_window(
|
||
movable_=false
|
||
, "alert box"
|
||
);
|
||
window\* w = new_window(
|
||
"alert box"
|
||
, movable_=false
|
||
);
|
||
|
||
.. @ignore()
|
||
|
||
The goal this time is to be able to invoke the ``new_window`` function without
|
||
specifying the keywords. For each parameter that has a required type, we can
|
||
enclose that type in parentheses, then *replace* the ``*`` element of the
|
||
parameter signature:
|
||
|
||
.. parsed-literal::
|
||
|
||
BOOST_PARAMETER_NAME((name\_, keywords) name)
|
||
BOOST_PARAMETER_NAME((movable\_, keywords) movable)
|
||
|
||
BOOST_PARAMETER_FUNCTION((window\*), new_window, keywords,
|
||
(deduced
|
||
(required
|
||
(name, *(char const\*)*)
|
||
(movable, *(bool)*)
|
||
)
|
||
)
|
||
)
|
||
{
|
||
// ...
|
||
}
|
||
|
||
.. @ignore()
|
||
|
||
The following statements will now work and are equivalent to each other as
|
||
well as the previous statements:
|
||
|
||
.. parsed-literal::
|
||
|
||
window\* w = new_window(false, "alert box");
|
||
window\* w = new_window("alert box", false);
|
||
|
||
.. @ignore()
|
||
|
||
Deduced Parameters
|
||
------------------
|
||
|
||
To further illustrate deduced parameter support, consider the example of the
|
||
|def|_ function from Boost.Python_. Its signature is roughly as follows:
|
||
|
||
.. parsed-literal::
|
||
|
||
template <
|
||
typename Function
|
||
, typename KeywordExpression
|
||
, typename CallPolicies
|
||
>
|
||
void def(
|
||
// Required parameters
|
||
char const\* name, Function func
|
||
|
||
// Optional, deduced parameters
|
||
, char const\* docstring = ""
|
||
, KeywordExpression keywords = no_keywords()
|
||
, CallPolicies policies = default_call_policies()
|
||
);
|
||
|
||
.. @ignore()
|
||
|
||
Try not to be too distracted by the use of the term “keywords” in this
|
||
example: although it means something analogous in Boost.Python to what
|
||
it means in the Parameter library, for the purposes of this exercise
|
||
you can think of it as being completely different.
|
||
|
||
When calling ``def``, only two arguments are required. The association
|
||
between any additional arguments and their parameters can be determined by the
|
||
types of the arguments actually passed, so the caller is neither required to
|
||
remember argument positions or explicitly specify parameter names for those
|
||
arguments. To generate this interface using ``BOOST_PARAMETER_FUNCTION``, we
|
||
need only enclose the deduced parameters in a ``(deduced …)`` clause, as
|
||
follows:
|
||
|
||
.. parsed-literal::
|
||
|
||
char const*& blank_char_ptr()
|
||
{
|
||
static char const* larr = "";
|
||
return larr;
|
||
}
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(bool), def, tag,
|
||
|
||
(required (name, (char const\*)) (func,\*) ) // nondeduced
|
||
|
||
**(deduced**
|
||
(optional
|
||
(docstring, (char const\*), "")
|
||
|
||
(keywords
|
||
// see [#is_keyword_expression]_
|
||
, \*(is_keyword_expression<boost::mpl::_>)
|
||
, no_keywords()
|
||
)
|
||
|
||
(policies
|
||
, \*(
|
||
boost::mpl::eval_if<
|
||
boost::is_convertible<boost::mpl::_,char const\*>
|
||
, boost::mpl::false\_
|
||
, boost::mpl::if_<
|
||
// see [#is_keyword_expression]_
|
||
is_keyword_expression<boost::mpl::_>
|
||
, boost::mpl::false\_
|
||
, boost::mpl::true\_
|
||
>
|
||
>
|
||
)
|
||
, default_call_policies()
|
||
)
|
||
)
|
||
**)**
|
||
)
|
||
{
|
||
*…*
|
||
}
|
||
|
||
.. @example.replace_emphasis('return true;')
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
|
||
BOOST_PARAMETER_NAME(name)
|
||
BOOST_PARAMETER_NAME(func)
|
||
BOOST_PARAMETER_NAME(docstring)
|
||
BOOST_PARAMETER_NAME(keywords)
|
||
BOOST_PARAMETER_NAME(policies)
|
||
|
||
struct default_call_policies
|
||
{
|
||
};
|
||
|
||
struct no_keywords
|
||
{
|
||
};
|
||
|
||
struct keywords
|
||
{
|
||
};
|
||
|
||
template <typename T>
|
||
struct is_keyword_expression
|
||
: boost::mpl::false_
|
||
{
|
||
};
|
||
|
||
template <>
|
||
struct is_keyword_expression<keywords>
|
||
: boost::mpl::true_
|
||
{
|
||
};
|
||
|
||
default_call_policies some_policies;
|
||
|
||
void f()
|
||
{
|
||
}
|
||
|
||
#include <boost/mpl/placeholders.hpp>
|
||
#include <boost/mpl/if.hpp>
|
||
#include <boost/mpl/eval_if.hpp>
|
||
#include <boost/type_traits/is_convertible.hpp>
|
||
|
||
''')
|
||
|
||
.. Admonition:: Syntax Note
|
||
|
||
A ``(deduced …)`` clause always contains a ``(required …)`` and/or an
|
||
``(optional …)`` subclause, and must follow any ``(required …)`` or
|
||
``(optional …)`` clauses indicating nondeduced parameters at the outer
|
||
level.
|
||
|
||
With the declaration above, the following two calls are equivalent:
|
||
|
||
.. parsed-literal::
|
||
|
||
char const\* f_name = "f";
|
||
def(
|
||
f_name
|
||
, &f
|
||
, **some_policies**
|
||
, **"Documentation for f"**
|
||
);
|
||
def(
|
||
f_name
|
||
, &f
|
||
, **"Documentation for f"**
|
||
, **some_policies**
|
||
);
|
||
|
||
.. @example.prepend('''
|
||
int main()
|
||
{
|
||
''')
|
||
|
||
If the user wants to pass a ``policies`` argument that was also, for some
|
||
reason, convertible to ``char const*``, she can always specify the parameter
|
||
name explicitly, as follows:
|
||
|
||
.. parsed-literal::
|
||
|
||
def(
|
||
f_name
|
||
, &f
|
||
, **_policies = some_policies**
|
||
, "Documentation for f"
|
||
);
|
||
|
||
.. @example.append('}')
|
||
.. @test('compile', howmany='all')
|
||
|
||
The |deduced_cpp|_ and |deduced_dependent_predicate|_ test programs
|
||
demonstrate additional usage of deduced parameter support.
|
||
|
||
.. _Boost.Python: ../../../python/doc/index.html
|
||
.. |def| replace:: ``def``
|
||
.. _def: ../../../python/doc/v2/def.html
|
||
.. |deduced_cpp| replace:: deduced.cpp
|
||
.. _deduced_cpp: ../../test/deduced.cpp
|
||
.. |deduced_dependent_predicate| replace:: deduced_dependent_predicate.cpp
|
||
.. _deduced_dependent_predicate: ../../test/deduced_dependent_predicate.cpp
|
||
|
||
Parameter-Dependent Return Types
|
||
--------------------------------
|
||
|
||
For some algorithms, the return type depends on at least one of the argument
|
||
types. However, there is one gotcha to avoid when encoding this return type
|
||
while using ``BOOST_PARAMETER_FUNCTION`` or other code generation macros. As
|
||
an example, given the following definitions::
|
||
|
||
BOOST_PARAMETER_NAME(x)
|
||
BOOST_PARAMETER_NAME(y)
|
||
BOOST_PARAMETER_NAME(z)
|
||
|
||
.. @ignore()
|
||
|
||
Let our algorithm simply return one of its arguments. If we naïvely implement
|
||
its return type in terms of ``parameter::value_type``::
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(typename parameter::value_type<Args,tag::y>::type), return_y, tag,
|
||
(deduced
|
||
(required
|
||
(x, (std::map<char const*,std::string>))
|
||
(y, (char const*))
|
||
)
|
||
(optional
|
||
(z, (int), 4)
|
||
)
|
||
)
|
||
)
|
||
{
|
||
return y;
|
||
}
|
||
|
||
.. @ignore()
|
||
|
||
Then using ``return_y`` in any manner other than with positional arguments
|
||
will result in a compiler error::
|
||
|
||
std::map<char const*,std::string> k2s;
|
||
assert("foo" == return_y(2, k2s, "foo")); // error!
|
||
|
||
.. @ignore()
|
||
|
||
The problem is that even though ``y`` is a required parameter,
|
||
``BOOST_PARAMETER_FUNCTION`` will generate certain overloads for which the
|
||
argument pack type ``Args`` does not actually contain the keyword tag type
|
||
``tag::y``. The solution is to use SFINAE to preclude generation of those
|
||
overloads. Since ``parameter::value_type`` is a metafunction, our tool for
|
||
the job is ``lazy_enable_if``::
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(
|
||
// Whenever using 'enable_if', 'disable_if', and so on,
|
||
// do not add the 'typename' keyword in front.
|
||
boost::lazy_enable_if<
|
||
typename mpl::has_key<Args,tag::y>::type
|
||
, parameter::value_type<Args,tag::y>
|
||
>
|
||
// Whenever using 'enable_if', 'disable_if', and so on,
|
||
// do not add '::type' here.
|
||
), return_y, tag,
|
||
(deduced
|
||
(required
|
||
(x, (std::map<char const*,std::string>))
|
||
(y, (char const*))
|
||
)
|
||
(optional
|
||
(z, (int), 4)
|
||
)
|
||
)
|
||
)
|
||
{
|
||
return y;
|
||
}
|
||
|
||
.. @ignore()
|
||
|
||
For a working demonstration, see |preprocessor_deduced_cpp|_.
|
||
|
||
.. |preprocessor_deduced_cpp| replace:: preprocessor_deduced.cpp
|
||
.. _preprocessor_deduced_cpp: ../../test/preprocessor_deduced.cpp
|
||
|
||
----------------------------------
|
||
Parameter-Enabled Member Functions
|
||
----------------------------------
|
||
|
||
The ``BOOST_PARAMETER_MEMBER_FUNCTION`` and
|
||
``BOOST_PARAMETER_CONST_MEMBER_FUNCTION`` macros accept exactly the same
|
||
arguments as ``BOOST_PARAMETER_FUNCTION``, but are designed to be used within
|
||
the body of a class::
|
||
|
||
BOOST_PARAMETER_NAME(arg1)
|
||
BOOST_PARAMETER_NAME(arg2)
|
||
|
||
struct callable2
|
||
{
|
||
BOOST_PARAMETER_CONST_MEMBER_FUNCTION(
|
||
(void), call, tag, (required (arg1,(int))(arg2,(int)))
|
||
)
|
||
{
|
||
std::cout << arg1 << ", " << arg2;
|
||
std::cout << std::endl;
|
||
}
|
||
};
|
||
|
||
#include <boost/core/lightweight_test.hpp>
|
||
|
||
int main()
|
||
{
|
||
callable2 c2;
|
||
callable2 const& c2_const = c2;
|
||
c2_const.call(1, 2);
|
||
return boost::report_errors();
|
||
}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <iostream>
|
||
using namespace boost::parameter;
|
||
''')
|
||
|
||
.. @test('run')
|
||
|
||
These macros don't directly allow a function's interface to be separated from
|
||
its implementation, but you can always forward arguments on to a separate
|
||
implementation function::
|
||
|
||
struct callable2
|
||
{
|
||
BOOST_PARAMETER_CONST_MEMBER_FUNCTION(
|
||
(void), call, tag, (required (arg1,(int))(arg2,(int)))
|
||
)
|
||
{
|
||
call_impl(arg1, arg2);
|
||
}
|
||
|
||
private:
|
||
void call_impl(int, int); // implemented elsewhere.
|
||
};
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
|
||
BOOST_PARAMETER_NAME(arg1)
|
||
BOOST_PARAMETER_NAME(arg2)
|
||
using namespace boost::parameter;
|
||
''')
|
||
|
||
.. @test('compile')
|
||
|
||
Static Member Functions
|
||
=======================
|
||
|
||
To expose a static member function, simply insert the keyword “``static``”
|
||
before the function name:
|
||
|
||
.. parsed-literal::
|
||
|
||
BOOST_PARAMETER_NAME(arg1)
|
||
|
||
struct somebody
|
||
{
|
||
BOOST_PARAMETER_MEMBER_FUNCTION(
|
||
(void), **static** f, tag, (optional (arg1,(int),0))
|
||
)
|
||
{
|
||
std::cout << arg1 << std::endl;
|
||
}
|
||
};
|
||
|
||
#include <boost/core/lightweight_test.hpp>
|
||
|
||
int main()
|
||
{
|
||
somebody::f();
|
||
somebody::f(4);
|
||
return boost::report_errors();
|
||
}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <iostream>
|
||
using namespace boost::parameter;
|
||
''')
|
||
|
||
.. @test('run')
|
||
|
||
-----------------------------------------
|
||
Parameter-Enabled Function Call Operators
|
||
-----------------------------------------
|
||
|
||
The ``BOOST_PARAMETER_FUNCTION_CALL_OPERATOR`` and
|
||
``BOOST_PARAMETER_CONST_FUNCTION_CALL_OPERATOR`` macros accept the same
|
||
arguments as the ``BOOST_PARAMETER_MEMBER_FUNCTION`` and
|
||
``BOOST_PARAMETER_CONST_MEMBER_FUNCTION`` macros except for the function name,
|
||
because these macros allow instances of the enclosing classes to be treated as
|
||
function objects::
|
||
|
||
BOOST_PARAMETER_NAME(first_arg)
|
||
BOOST_PARAMETER_NAME(second_arg)
|
||
|
||
struct callable2
|
||
{
|
||
BOOST_PARAMETER_CONST_FUNCTION_CALL_OPERATOR(
|
||
(void), tag, (required (first_arg,(int))(second_arg,(int)))
|
||
)
|
||
{
|
||
std::cout << first_arg << ", ";
|
||
std::cout << second_arg << std::endl;
|
||
}
|
||
};
|
||
|
||
#include <boost/core/lightweight_test.hpp>
|
||
|
||
int main()
|
||
{
|
||
callable2 c2;
|
||
callable2 const& c2_const = c2;
|
||
c2_const(1, 2);
|
||
return boost::report_errors();
|
||
}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <iostream>
|
||
using namespace boost::parameter;
|
||
''')
|
||
|
||
.. @test('run')
|
||
|
||
------------------------------
|
||
Parameter-Enabled Constructors
|
||
------------------------------
|
||
|
||
The lack of a “delegating constructor” feature in C++
|
||
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf)
|
||
limits somewhat the quality of interface this library can provide
|
||
for defining parameter-enabled constructors. The usual workaround
|
||
for a lack of constructor delegation applies: one must factor the
|
||
common logic into one or more base classes.
|
||
|
||
Let's build a parameter-enabled constructor that simply prints its
|
||
arguments. The first step is to write a base class whose
|
||
constructor accepts a single argument known as an |ArgumentPack|_:
|
||
a bundle of references to the actual arguments, tagged with their
|
||
keywords. The values of the actual arguments are extracted from
|
||
the |ArgumentPack| by *indexing* it with keyword objects::
|
||
|
||
BOOST_PARAMETER_NAME(name)
|
||
BOOST_PARAMETER_NAME(index)
|
||
|
||
struct myclass_impl
|
||
{
|
||
template <typename ArgumentPack>
|
||
myclass_impl(ArgumentPack const& args)
|
||
{
|
||
std::cout << "name = " << args[_name];
|
||
std::cout << "; index = " << args[_index | 42];
|
||
std::cout << std::endl;
|
||
}
|
||
};
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <iostream>
|
||
''')
|
||
|
||
Note that the bitwise or (“\ ``|``\ ”) operator has a special meaning when
|
||
applied to keyword objects that are passed to an |ArgumentPack|\ 's indexing
|
||
operator: it is used to indicate a default value. In this case if there is no
|
||
``index`` parameter in the |ArgumentPack|, ``42`` will be used instead.
|
||
|
||
Now we are ready to write the parameter-enabled constructor interface::
|
||
|
||
struct myclass : myclass_impl
|
||
{
|
||
BOOST_PARAMETER_CONSTRUCTOR(
|
||
myclass, (myclass_impl), tag
|
||
, (required (name,*)) (optional (index,*))
|
||
) // no semicolon
|
||
};
|
||
|
||
Since we have supplied a default value for ``index`` but not for ``name``,
|
||
only ``name`` is required. We can exercise our new interface as follows::
|
||
|
||
myclass x("bob", 3); // positional
|
||
myclass y(_index = 12, _name = "sally"); // named
|
||
myclass z("june"); // positional/defaulted
|
||
|
||
.. @example.wrap('''
|
||
#include <boost/core/lightweight_test.hpp>
|
||
|
||
int main() {
|
||
''', ' return boost::report_errors(); }')
|
||
.. @test('run', howmany='all')
|
||
|
||
For more on |ArgumentPack| manipulation, see the `Advanced Topics`_ section.
|
||
|
||
---------------------------------
|
||
Parameter-Enabled Class Templates
|
||
---------------------------------
|
||
|
||
In this section we'll use Boost.Parameter to build Boost.Python_\
|
||
's `class_`_ template, whose “signature” is:
|
||
|
||
.. parsed-literal::
|
||
|
||
template <
|
||
ValueType, BaseList = bases<>
|
||
, HeldType = ValueType, Copyable = void
|
||
>
|
||
class class\_;
|
||
|
||
.. @ignore()
|
||
|
||
Only the first argument, ``ValueType``, is required.
|
||
|
||
.. _class_: http://www.boost.org/libs/python/doc/v2/class.html#class_-spec
|
||
|
||
Named Template Parameters
|
||
=========================
|
||
|
||
First, we'll build an interface that allows users to pass arguments
|
||
positionally or by name:
|
||
|
||
.. parsed-literal::
|
||
|
||
struct B
|
||
{
|
||
virtual ~B() = 0;
|
||
};
|
||
|
||
struct D : B
|
||
{
|
||
~D();
|
||
};
|
||
|
||
class_<
|
||
**class_type<B>**
|
||
, **copyable<boost::noncopyable>**
|
||
> …;
|
||
|
||
class_<
|
||
**D**
|
||
, **held_type<std::auto_ptr<D> >**
|
||
, **base_list<bases<B> >**
|
||
> …;
|
||
|
||
.. @ignore()
|
||
|
||
Template Keywords
|
||
-----------------
|
||
|
||
The first step is to define keywords for each template parameter::
|
||
|
||
namespace boost { namespace python {
|
||
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable)
|
||
}}
|
||
|
||
.. @example.prepend('#include <boost/parameter.hpp>')
|
||
.. @test('compile')
|
||
|
||
The declaration of the ``class_type`` keyword you see here is equivalent to::
|
||
|
||
namespace boost { namespace python {
|
||
namespace tag {
|
||
|
||
struct class_type; // keyword tag type
|
||
}
|
||
|
||
template <typename T>
|
||
struct class_type
|
||
: parameter::template_keyword<tag::class_type,T>
|
||
{
|
||
};
|
||
}}
|
||
|
||
.. @example.prepend('#include <boost/parameter.hpp>')
|
||
.. @test('compile')
|
||
|
||
It defines a keyword tag type named ``tag::class_type`` and a
|
||
*parameter passing template* named ``class_type``.
|
||
|
||
Class Template Skeleton
|
||
-----------------------
|
||
|
||
The next step is to define the skeleton of our class template, which has three
|
||
optional parameters. Because the user may pass arguments in any order, we
|
||
don't know the actual identities of these parameters, so it would be premature
|
||
to use descriptive names or write out the actual default values for any of
|
||
them. Instead, we'll give them generic names and use the special type
|
||
``boost::parameter::void_`` as a default:
|
||
|
||
.. parsed-literal::
|
||
|
||
namespace boost { namespace python {
|
||
|
||
template <
|
||
typename A0
|
||
, typename A1 = boost::parameter::void\_
|
||
, typename A2 = boost::parameter::void\_
|
||
, typename A3 = boost::parameter::void\_
|
||
>
|
||
struct class\_
|
||
{
|
||
*…*
|
||
};
|
||
}}
|
||
|
||
.. @example.prepend('#include <boost/parameter.hpp>')
|
||
.. @example.replace_emphasis('')
|
||
.. @test('compile')
|
||
|
||
Class Template Signatures
|
||
-------------------------
|
||
|
||
Next, we need to build a type, known as a |ParameterSpec|_, describing the
|
||
“signature” of ``boost::python::class_``. A |ParameterSpec|_ enumerates the
|
||
required and optional parameters in their positional order, along with any
|
||
type requirements (note that it does *not* specify defaults -- those will be
|
||
dealt with separately)::
|
||
|
||
namespace boost { namespace python {
|
||
|
||
using boost::mpl::_;
|
||
|
||
typedef parameter::parameters<
|
||
required<tag::class_type, boost::is_class<_> >
|
||
, parameter::optional<tag::base_list, mpl::is_sequence<_> >
|
||
, parameter::optional<tag::held_type>
|
||
, parameter::optional<tag::copyable>
|
||
> class_signature;
|
||
}}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <boost/mpl/is_sequence.hpp>
|
||
#include <boost/noncopyable.hpp>
|
||
#include <boost/type_traits/is_class.hpp>
|
||
#include <memory>
|
||
|
||
using namespace boost::parameter;
|
||
|
||
namespace boost { namespace python {
|
||
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable)
|
||
|
||
template <typename B = int>
|
||
struct bases
|
||
{
|
||
};
|
||
}}
|
||
''')
|
||
|
||
.. |ParameterSpec| replace:: :concept:`ParameterSpec`
|
||
|
||
.. _ParameterSpec: reference.html#parameterspec
|
||
|
||
.. _binding_intro:
|
||
|
||
Argument Packs and Parameter Extraction
|
||
---------------------------------------
|
||
|
||
Next, within the body of ``class_`` , we use the |ParameterSpec|\ 's
|
||
nested ``::bind< … >`` template to bundle the actual arguments into an
|
||
|ArgumentPack|_ type, and then use the library's ``value_type< … >``
|
||
metafunction to extract “logical parameters”. ``value_type< … >`` is
|
||
a lot like ``binding< … >``, but no reference is added to the actual
|
||
argument type. Note that defaults are specified by passing it an
|
||
optional third argument::
|
||
|
||
namespace boost { namespace python {
|
||
|
||
template <
|
||
typename A0
|
||
, typename A1 = boost::parameter::void_
|
||
, typename A2 = boost::parameter::void_
|
||
, typename A3 = boost::parameter::void_
|
||
>
|
||
struct class_
|
||
{
|
||
// Create ArgumentPack
|
||
typedef typename class_signature::template bind<
|
||
A0, A1, A2, A3
|
||
>::type args;
|
||
|
||
// Extract first logical parameter.
|
||
typedef typename parameter::value_type<
|
||
args, tag::class_type
|
||
>::type class_type;
|
||
|
||
typedef typename parameter::value_type<
|
||
args, tag::base_list, bases<>
|
||
>::type base_list;
|
||
|
||
typedef typename parameter::value_type<
|
||
args, tag::held_type, class_type
|
||
>::type held_type;
|
||
|
||
typedef typename parameter::value_type<
|
||
args, tag::copyable, void
|
||
>::type copyable;
|
||
};
|
||
}}
|
||
|
||
.. |ArgumentPack| replace:: :concept:`ArgumentPack`
|
||
.. _ArgumentPack: reference.html#argumentpack
|
||
|
||
Exercising the Code So Far
|
||
==========================
|
||
|
||
.. compound::
|
||
|
||
Revisiting our original examples, ::
|
||
|
||
typedef boost::python::class_<
|
||
class_type<B>, copyable<boost::noncopyable>
|
||
> c1;
|
||
|
||
typedef boost::python::class_<
|
||
D
|
||
, held_type<std::auto_ptr<D> >
|
||
, base_list<bases<B> >
|
||
> c2;
|
||
|
||
.. @example.prepend('''
|
||
using boost::python::class_type;
|
||
using boost::python::copyable;
|
||
using boost::python::held_type;
|
||
using boost::python::base_list;
|
||
using boost::python::bases;
|
||
|
||
struct B
|
||
{
|
||
};
|
||
|
||
struct D
|
||
{
|
||
};
|
||
''')
|
||
|
||
we can now examine the intended parameters::
|
||
|
||
BOOST_MPL_ASSERT((boost::is_same<c1::class_type, B>));
|
||
BOOST_MPL_ASSERT((boost::is_same<c1::base_list, bases<> >));
|
||
BOOST_MPL_ASSERT((boost::is_same<c1::held_type, B>));
|
||
BOOST_MPL_ASSERT((
|
||
boost::is_same<c1::copyable, boost::noncopyable>
|
||
));
|
||
|
||
BOOST_MPL_ASSERT((boost::is_same<c2::class_type, D>));
|
||
BOOST_MPL_ASSERT((boost::is_same<c2::base_list, bases<B> >));
|
||
BOOST_MPL_ASSERT((
|
||
boost::is_same<c2::held_type, std::auto_ptr<D> >
|
||
));
|
||
BOOST_MPL_ASSERT((boost::is_same<c2::copyable, void>));
|
||
|
||
.. @test('compile', howmany='all')
|
||
|
||
Deduced Template Parameters
|
||
===========================
|
||
|
||
To apply a deduced parameter interface here, we need only make the type
|
||
requirements a bit tighter so the ``held_type`` and ``copyable`` parameters
|
||
can be crisply distinguished from the others. Boost.Python_ does this by
|
||
requiring that ``base_list`` be a specialization of its ``bases< … >``
|
||
template (as opposed to being any old MPL sequence) and by requiring that
|
||
``copyable``, if explicitly supplied, be ``boost::noncopyable``. One easy way
|
||
of identifying specializations of ``bases< … >`` is to derive them all from
|
||
the same class, as an implementation detail:
|
||
|
||
.. parsed-literal::
|
||
|
||
namespace boost { namespace python {
|
||
namespace detail {
|
||
|
||
struct bases_base
|
||
{
|
||
};
|
||
}
|
||
|
||
template <
|
||
typename A0 = void, typename A1 = void, typename A2 = void *…*
|
||
>
|
||
struct bases **: detail::bases_base**
|
||
{
|
||
};
|
||
}}
|
||
|
||
.. @example.replace_emphasis('')
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <boost/mpl/is_sequence.hpp>
|
||
#include <boost/noncopyable.hpp>
|
||
#include <memory>
|
||
|
||
using namespace boost::parameter;
|
||
using boost::mpl::_;
|
||
|
||
namespace boost { namespace python {
|
||
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type)
|
||
BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable)
|
||
}}
|
||
''')
|
||
|
||
Now we can rewrite our signature to make all three optional parameters
|
||
deducible::
|
||
|
||
typedef parameter::parameters<
|
||
required<tag::class_type, is_class<_> >
|
||
|
||
, parameter::optional<
|
||
deduced<tag::base_list>
|
||
, is_base_and_derived<detail::bases_base,_>
|
||
>
|
||
|
||
, parameter::optional<
|
||
deduced<tag::held_type>
|
||
, mpl::not_<
|
||
mpl::or_<
|
||
is_base_and_derived<detail::bases_base,_>
|
||
, is_same<noncopyable,_>
|
||
>
|
||
>
|
||
>
|
||
|
||
, parameter::optional<
|
||
deduced<tag::copyable>
|
||
, is_same<noncopyable,_>
|
||
>
|
||
|
||
> class_signature;
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/type_traits/is_class.hpp>
|
||
namespace boost { namespace python {
|
||
''')
|
||
|
||
.. @example.append('''
|
||
template <
|
||
typename A0
|
||
, typename A1 = boost::parameter::void_
|
||
, typename A2 = boost::parameter::void_
|
||
, typename A3 = boost::parameter::void_
|
||
>
|
||
struct class_
|
||
{
|
||
// Create ArgumentPack
|
||
typedef typename class_signature::bind<
|
||
A0, A1, A2, A3
|
||
>::type args;
|
||
|
||
// Extract first logical parameter.
|
||
typedef typename parameter::value_type<
|
||
args, tag::class_type
|
||
>::type class_type;
|
||
|
||
typedef typename parameter::value_type<
|
||
args, tag::base_list, bases<>
|
||
>::type base_list;
|
||
|
||
typedef typename parameter::value_type<
|
||
args, tag::held_type, class_type
|
||
>::type held_type;
|
||
|
||
typedef typename parameter::value_type<
|
||
args, tag::copyable, void
|
||
>::type copyable;
|
||
};
|
||
}}
|
||
''')
|
||
|
||
It may seem like we've added a great deal of complexity, but the benefits to
|
||
our users are greater. Our original examples can now be written without
|
||
explicit parameter names:
|
||
|
||
.. parsed-literal::
|
||
|
||
typedef boost::python::class_<**B**, **boost::noncopyable**> c1;
|
||
|
||
typedef boost::python::class_<
|
||
**D**, **std::auto_ptr<D>**, **bases<B>**
|
||
> c2;
|
||
|
||
.. @example.prepend('''
|
||
struct B
|
||
{
|
||
};
|
||
|
||
struct D
|
||
{
|
||
};
|
||
|
||
using boost::python::bases;
|
||
''')
|
||
|
||
.. @example.append('''
|
||
BOOST_MPL_ASSERT((boost::is_same<c1::class_type, B>));
|
||
BOOST_MPL_ASSERT((boost::is_same<c1::base_list, bases<> >));
|
||
BOOST_MPL_ASSERT((boost::is_same<c1::held_type, B>));
|
||
BOOST_MPL_ASSERT((
|
||
boost::is_same<c1::copyable, boost::noncopyable>
|
||
));
|
||
|
||
BOOST_MPL_ASSERT((boost::is_same<c2::class_type, D>));
|
||
BOOST_MPL_ASSERT((boost::is_same<c2::base_list, bases<B> >));
|
||
BOOST_MPL_ASSERT((
|
||
boost::is_same<c2::held_type, std::auto_ptr<D> >
|
||
));
|
||
BOOST_MPL_ASSERT((boost::is_same<c2::copyable, void>));
|
||
''')
|
||
|
||
.. @test('compile', howmany='all')
|
||
|
||
===============
|
||
Advanced Topics
|
||
===============
|
||
|
||
At this point, you should have a good grasp of the basics. In this section
|
||
we'll cover some more esoteric uses of the library.
|
||
|
||
-------------------------
|
||
Fine-Grained Name Control
|
||
-------------------------
|
||
|
||
If you don't like the leading-underscore naming convention used to refer to
|
||
keyword objects, or you need the name ``tag`` for something other than the
|
||
keyword type namespace, there's another way to use ``BOOST_PARAMETER_NAME``:
|
||
|
||
.. parsed-literal::
|
||
|
||
BOOST_PARAMETER_NAME(
|
||
**(**
|
||
*object-name*
|
||
**,** *tag-namespace*
|
||
**)** *parameter-name*
|
||
)
|
||
|
||
.. @ignore()
|
||
|
||
Here is a usage example:
|
||
|
||
.. parsed-literal::
|
||
|
||
BOOST_PARAMETER_NAME(
|
||
(
|
||
**pass_foo**, **keywords**
|
||
) **foo**
|
||
)
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(int), f,
|
||
**keywords**, (required (**foo**, \*))
|
||
)
|
||
{
|
||
return **foo** + 1;
|
||
}
|
||
|
||
int x = f(**pass_foo** = 41);
|
||
|
||
.. @example.prepend('#include <boost/parameter.hpp>')
|
||
.. @example.append('''
|
||
int main()
|
||
{
|
||
return 0;
|
||
}
|
||
''')
|
||
.. @test('run')
|
||
|
||
Before you use this more verbose form, however, please read the section on
|
||
`best practices for keyword object naming`__.
|
||
|
||
__ `Keyword Naming`_
|
||
|
||
----------------------
|
||
More |ArgumentPack|\ s
|
||
----------------------
|
||
|
||
We've already seen |ArgumentPack|\ s when we looked at
|
||
`parameter-enabled constructors`_ and `class templates`__. As you
|
||
might have guessed, |ArgumentPack|\ s actually lie at the heart of
|
||
everything this library does; in this section we'll examine ways to
|
||
build and manipulate them more effectively.
|
||
|
||
__ binding_intro_
|
||
|
||
Building |ArgumentPack|\ s
|
||
==========================
|
||
|
||
The simplest |ArgumentPack| is the result of assigning into a keyword object::
|
||
|
||
BOOST_PARAMETER_NAME(index)
|
||
|
||
template <typename ArgumentPack>
|
||
int print_index(ArgumentPack const& args)
|
||
{
|
||
std::cout << "index = " << args[_index];
|
||
std::cout << std::endl;
|
||
return 0;
|
||
}
|
||
|
||
int x = print_index(_index = 3); // prints "index = 3"
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <iostream>
|
||
''')
|
||
|
||
Also, |ArgumentPack|\ s can be composed using the comma operator. The extra
|
||
parentheses below are used to prevent the compiler from seeing two separate
|
||
arguments to ``print_name_and_index``::
|
||
|
||
BOOST_PARAMETER_NAME(name)
|
||
|
||
template <typename ArgumentPack>
|
||
int print_name_and_index(ArgumentPack const& args)
|
||
{
|
||
std::cout << "name = " << args[_name];
|
||
std::cout << "; ";
|
||
return print_index(args);
|
||
}
|
||
|
||
int y = print_name_and_index((_index = 3, _name = "jones"));
|
||
|
||
The |compose_cpp|_ test program shows more examples of this feature.
|
||
|
||
To build an |ArgumentPack| with positional arguments, we can use a
|
||
|ParameterSpec|_. As introduced described in the section on `Class Template
|
||
Signatures`_, a |ParameterSpec| describes the positional order of parameters
|
||
and any associated type requirements. Just as we can build an |ArgumentPack|
|
||
*type* with its nested ``::bind< … >`` template, we can build an
|
||
|ArgumentPack| *object* by invoking its function call operator:
|
||
|
||
.. parsed-literal::
|
||
|
||
parameter::parameters<
|
||
required<tag::\ name, is_convertible<_,char const*> >
|
||
, optional<tag::\ index, is_convertible<_,int> >
|
||
> spec;
|
||
|
||
char const sam[] = "sam";
|
||
int twelve = 12;
|
||
|
||
int z0 = print_name_and_index(
|
||
**spec(** sam, twelve **)**
|
||
);
|
||
|
||
int z1 = print_name_and_index(
|
||
**spec(** _index=12, _name="sam" **)**
|
||
);
|
||
|
||
.. @example.prepend('''
|
||
namespace parameter = boost::parameter;
|
||
using parameter::required;
|
||
using parameter::optional;
|
||
using boost::is_convertible;
|
||
using boost::mpl::_;
|
||
''')
|
||
|
||
.. @example.append('''
|
||
int main()
|
||
{
|
||
return 0;
|
||
}
|
||
''')
|
||
|
||
.. @test('run', howmany='all')
|
||
|
||
Extracting Parameter Types
|
||
==========================
|
||
|
||
If we want to know the types of the arguments passed to
|
||
``print_name_and_index``, we have a couple of options. The
|
||
simplest and least error-prone approach is to forward them to a
|
||
function template and allow *it* to do type deduction::
|
||
|
||
BOOST_PARAMETER_NAME(name)
|
||
BOOST_PARAMETER_NAME(index)
|
||
|
||
template <typename Name, typename Index>
|
||
int deduce_arg_types_impl(Name&& name, Index&& index)
|
||
{
|
||
// we know the types
|
||
Name&& n2 = boost::forward<Name>(name);
|
||
Index&& i2 = boost::forward<Index>(index);
|
||
return index;
|
||
}
|
||
|
||
template <typename ArgumentPack>
|
||
int deduce_arg_types(ArgumentPack const& args)
|
||
{
|
||
return deduce_arg_types_impl(args[_name], args[_index | 42]);
|
||
}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
''')
|
||
|
||
.. @example.append('''
|
||
#include <boost/core/lightweight_test.hpp>
|
||
|
||
int main()
|
||
{
|
||
int a1 = deduce_arg_types((_name = "foo"));
|
||
int a2 = deduce_arg_types((_name = "foo", _index = 3));
|
||
BOOST_TEST_EQ(a1, 42);
|
||
BOOST_TEST_EQ(a2, 3);
|
||
return boost::report_errors();
|
||
}
|
||
''')
|
||
|
||
.. @test('run')
|
||
|
||
Occasionally one needs to deduce argument types without an extra layer of
|
||
function call. For example, suppose we wanted to return twice the value of
|
||
the ``index`` parameter? In that case we can use the ``value_type< … >``
|
||
metafunction introduced `earlier`__::
|
||
|
||
BOOST_PARAMETER_NAME(index)
|
||
|
||
template <typename ArgumentPack>
|
||
typename boost::parameter::value_type<ArgumentPack,tag::index,int>::type
|
||
twice_index(ArgumentPack const& args)
|
||
{
|
||
return 2 * args[_index | 42];
|
||
}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
''')
|
||
|
||
.. @example.append('''
|
||
#include <boost/core/lightweight_test.hpp>
|
||
|
||
int main()
|
||
{
|
||
int six = twice_index(_index = 3);
|
||
BOOST_TEST_EQ(six, 6);
|
||
return boost::report_errors();
|
||
}
|
||
''')
|
||
|
||
.. @test('run', howmany='all')
|
||
|
||
Note that if we had used ``binding< … >`` rather than ``value_type< … >``, we
|
||
would end up returning a reference to the temporary created in the ``2 * …``
|
||
expression.
|
||
|
||
__ binding_intro_
|
||
|
||
Lazy Default Computation
|
||
========================
|
||
|
||
When a default value is expensive to compute, it would be preferable to avoid
|
||
it until we're sure it's absolutely necessary. ``BOOST_PARAMETER_FUNCTION``
|
||
takes care of that problem for us, but when using |ArgumentPack|\ s
|
||
explicitly, we need a tool other than ``operator|``::
|
||
|
||
BOOST_PARAMETER_NAME(s1)
|
||
BOOST_PARAMETER_NAME(s2)
|
||
BOOST_PARAMETER_NAME(s3)
|
||
|
||
template <typename ArgumentPack>
|
||
std::string f(ArgumentPack const& args)
|
||
{
|
||
std::string const& s1 = args[_s1];
|
||
std::string const& s2 = args[_s2];
|
||
typename parameter::binding<
|
||
ArgumentPack,tag::s3,std::string
|
||
>::type s3 = args[_s3 | (s1 + s2)]; // always constructs s1 + s2
|
||
return s3;
|
||
}
|
||
|
||
std::string x = f((
|
||
_s1="hello,", _s2=" world", _s3="hi world"
|
||
));
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <string>
|
||
|
||
namespace parameter = boost::parameter;
|
||
''')
|
||
|
||
.. @example.append('''
|
||
int main()
|
||
{
|
||
return 0;
|
||
}
|
||
''')
|
||
|
||
.. @test('run')
|
||
|
||
In the example above, the string ``"hello, world"`` is constructed despite the
|
||
fact that the user passed us a value for ``s3``. To remedy that, we can
|
||
compute the default value *lazily* (that is, only on demand), by using
|
||
``boost::bind()`` to create a function object.
|
||
|
||
.. danielw: I'm leaving the text below in the source, because we might
|
||
.. want to change back to it after 1.34, and if I remove it now we
|
||
.. might forget about it.
|
||
|
||
.. by combining the logical-or (“``||``”) operator
|
||
.. with a function object built by the Boost Lambda_ library: [#bind]_
|
||
|
||
.. parsed-literal::
|
||
|
||
typename parameter::binding<
|
||
ArgumentPack,tag::s3,std::string
|
||
>::type s3 = args[
|
||
_s3 **|| boost::bind(
|
||
std::plus<std::string>(), boost::ref(s1), boost::ref(s2)
|
||
)**
|
||
];
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/bind.hpp>
|
||
#include <boost/ref.hpp>
|
||
#include <boost/parameter.hpp>
|
||
#include <string>
|
||
#include <functional>
|
||
|
||
namespace parameter = boost::parameter;
|
||
|
||
BOOST_PARAMETER_NAME(s1)
|
||
BOOST_PARAMETER_NAME(s2)
|
||
BOOST_PARAMETER_NAME(s3)
|
||
|
||
template <typename ArgumentPack>
|
||
std::string f(ArgumentPack const& args)
|
||
{
|
||
std::string const& s1 = args[_s1];
|
||
std::string const& s2 = args[_s2];
|
||
''')
|
||
|
||
.. @example.append('''
|
||
return s3;
|
||
}
|
||
|
||
std::string x = f((_s1="hello,", _s2=" world", _s3="hi world"));
|
||
|
||
int main()
|
||
{
|
||
return 0;
|
||
}
|
||
''')
|
||
|
||
.. @test('run')
|
||
|
||
.. .. _Lambda: ../../../lambda/index.html
|
||
|
||
.. 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.
|
||
|
||
The expression ``bind(std::plus<std::string>(), ref(s1), ref(s2))`` yields a
|
||
*function object* that, when invoked, adds the two strings together. That
|
||
function will only be invoked if no ``s3`` argument is supplied by the caller.
|
||
|
||
.. The expression ``lambda::var(s1) + lambda::var(s2)`` yields a
|
||
.. *function object* that, when invoked, adds the two strings
|
||
.. together. That function will only be invoked if no ``s3`` argument
|
||
.. is supplied by the caller.
|
||
|
||
==============
|
||
Best Practices
|
||
==============
|
||
|
||
By now you should have a fairly good idea of how to use the Parameter
|
||
library. This section points out a few more-marginal issues that will help
|
||
you use the library more effectively.
|
||
|
||
--------------
|
||
Keyword Naming
|
||
--------------
|
||
|
||
``BOOST_PARAMETER_NAME`` prepends a leading underscore to the names of all our
|
||
keyword objects in order to avoid the following usually-silent bug:
|
||
|
||
.. parsed-literal::
|
||
|
||
namespace people
|
||
{
|
||
namespace tag
|
||
{
|
||
struct name
|
||
{
|
||
typedef boost::parameter::forward_reference qualifier;
|
||
};
|
||
|
||
struct age
|
||
{
|
||
typedef boost::parameter::forward_reference qualifier;
|
||
};
|
||
}
|
||
|
||
namespace // unnamed
|
||
{
|
||
boost::parameter::keyword<tag::name>& **name**
|
||
= boost::parameter::keyword<tag::name>::instance;
|
||
boost::parameter::keyword<tag::age>& **age**
|
||
= boost::parameter::keyword<tag::age>::instance;
|
||
}
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(void), g, tag, (optional (name, \*, "bob")(age, \*, 42))
|
||
)
|
||
{
|
||
std::cout << name << ":" << age;
|
||
}
|
||
|
||
void f(int age)
|
||
{
|
||
:vellipsis:`\
|
||
.
|
||
.
|
||
.
|
||
`
|
||
g(**age** = 3); // whoops!
|
||
}
|
||
}
|
||
|
||
.. @ignore()
|
||
|
||
Although in the case above, the user was trying to pass the value ``3`` as the
|
||
``age`` parameter to ``g``, what happened instead was that ``f``\ 's ``age``
|
||
argument got reassigned the value 3, and was then passed as a positional
|
||
argument to ``g``. Since ``g``'s first positional parameter is ``name``, the
|
||
default value for ``age`` is used, and g prints ``3:42``. Our leading
|
||
underscore naming convention makes this problem less likely to occur.
|
||
|
||
In this particular case, the problem could have been detected if f's ``age``
|
||
parameter had been made ``const``, which is always a good idea whenever
|
||
possible. Finally, we recommend that you use an enclosing namespace for all
|
||
your code, but particularly for names with leading underscores. If we were to
|
||
leave out the ``people`` namespace above, names in the global namespace
|
||
beginning with leading underscores—which are reserved to your C++
|
||
compiler—might become irretrievably ambiguous with those in our
|
||
unnamed namespace.
|
||
|
||
----------
|
||
Namespaces
|
||
----------
|
||
|
||
In our examples we've always declared keyword objects in (an unnamed namespace
|
||
within) the same namespace as the Boost.Parameter-enabled functions using
|
||
those keywords:
|
||
|
||
.. parsed-literal::
|
||
|
||
namespace lib {
|
||
|
||
**BOOST_PARAMETER_NAME(name)
|
||
BOOST_PARAMETER_NAME(index)**
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(int), f, tag,
|
||
(optional (name,*,"bob")(index,(int),1))
|
||
)
|
||
{
|
||
std::cout << name << ":" << index;
|
||
std::cout << std::endl;
|
||
return index;
|
||
}
|
||
}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <iostream>
|
||
''')
|
||
.. @namespace_setup = str(example)
|
||
.. @ignore()
|
||
|
||
Users of these functions have a few choices:
|
||
|
||
1. Full qualification:
|
||
|
||
.. parsed-literal::
|
||
|
||
int x = **lib::**\ f(
|
||
**lib::**\ _name = "jill"
|
||
, **lib::**\ _index = 1
|
||
);
|
||
|
||
This approach is more verbose than many users would like.
|
||
|
||
.. @example.prepend(namespace_setup)
|
||
.. @example.append('int main() { return 0; }')
|
||
.. @test('run')
|
||
|
||
2. Make keyword objects available through *using-declarations*:
|
||
|
||
.. parsed-literal::
|
||
|
||
**using lib::_name;
|
||
using lib::_index;**
|
||
|
||
int x = lib::f(_name = "jill", _index = 1);
|
||
|
||
This version is much better at the actual call site, but the
|
||
*using-declarations* themselves can be verbose and hard to manage.
|
||
|
||
.. @example.prepend(namespace_setup)
|
||
.. @example.append('int main() { return 0; }')
|
||
.. @test('run')
|
||
|
||
3. Bring in the entire namespace with a *using-directive*:
|
||
|
||
.. parsed-literal::
|
||
|
||
**using namespace lib;**
|
||
int x = **f**\ (_name = "jill", _index = 3);
|
||
|
||
This option is convenient, but it indiscriminately makes the *entire*
|
||
contents of ``lib`` available without qualification.
|
||
|
||
.. @example.prepend(namespace_setup)
|
||
.. @example.append('int main() { return 0; }')
|
||
.. @test('run')
|
||
|
||
If we add an additional namespace around keyword declarations, though, we can
|
||
give users more control:
|
||
|
||
.. parsed-literal::
|
||
|
||
namespace lib {
|
||
**namespace keywords {**
|
||
|
||
BOOST_PARAMETER_NAME(name)
|
||
BOOST_PARAMETER_NAME(index)
|
||
**}**
|
||
|
||
BOOST_PARAMETER_FUNCTION(
|
||
(int), f, **keywords::**\ tag,
|
||
(optional (name,*,"bob")(index,(int),1))
|
||
)
|
||
{
|
||
std::cout << name << ":" << index;
|
||
std::cout << std::endl;
|
||
return index;
|
||
}
|
||
}
|
||
|
||
.. @example.prepend('''
|
||
#include <boost/parameter.hpp>
|
||
#include <iostream>
|
||
''')
|
||
|
||
Now users need only a single *using-directive* to bring in just the names of
|
||
all keywords associated with ``lib``:
|
||
|
||
.. parsed-literal::
|
||
|
||
**using namespace lib::keywords;**
|
||
int y = lib::f(_name = "bob", _index = 2);
|
||
|
||
.. @example.append('int main() { return 0; }')
|
||
.. @test('run', howmany='all')
|
||
|
||
-------------
|
||
Documentation
|
||
-------------
|
||
|
||
The interface idioms enabled by Boost.Parameter are completely new (to C++),
|
||
and as such are not served by pre-existing documentation conventions.
|
||
|
||
.. Note:: This space is empty because we haven't settled on any best practices
|
||
yet. We'd be very pleased to link to your documentation if you've got a
|
||
style that you think is worth sharing.
|
||
|
||
==========================
|
||
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
|
||
|
||
--------------------------
|
||
Perfect Forwarding Support
|
||
--------------------------
|
||
|
||
If your compiler supports `perfect forwarding`_, then the Parameter library
|
||
will ``#define`` the macro ``BOOST_PARAMETER_HAS_PERFECT_FORWARDING`` unless
|
||
you disable it manually. If your compiler does not provide this support, then
|
||
``parameter::parameters::operator()`` will treat rvalue references as lvalue
|
||
``const`` references to work around the `forwarding problem`_, so in certain
|
||
cases you must wrap |boost_ref|_ or |std_ref|_ around any arguments that will
|
||
be bound to out parameters. The |evaluate_category|_ and
|
||
|preprocessor_eval_category|_ test programs demonstrate this support.
|
||
|
||
.. _`perfect forwarding`: http\://www.justsoftwaresolutions.co.uk/cplusplus/rvalue_references_and_perfect_forwarding.html
|
||
.. _`forwarding problem`: http\://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
|
||
.. |boost_ref| replace:: ``boost::ref``
|
||
.. _boost_ref: ../../../core/doc/html/core/ref.html
|
||
.. |std_ref| replace:: ``std::ref``
|
||
.. _std_ref: http://en.cppreference.com/w/cpp/utility/functional/ref
|
||
.. |evaluate_category| replace:: evaluate_category.cpp
|
||
.. _evaluate_category: ../../test/evaluate_category.cpp
|
||
.. |preprocessor_eval_category| replace:: preprocessor_eval_category.cpp
|
||
.. _preprocessor_eval_category: ../../test/preprocessor_eval_category.cpp
|
||
|
||
------------------
|
||
Boost.MP11 Support
|
||
------------------
|
||
|
||
If your compiler is sufficiently compliant with the C++11 standard, then the
|
||
Parameter library will ``#define`` the macro ``BOOST_PARAMETER_CAN_USE_MP11``
|
||
unless you disable it manually. The |singular_cpp|_, |compose_cpp|_,
|
||
|optional_deduced_sfinae_cpp|_, and |deduced_dep_pred_cpp|_ test programs
|
||
demonstrate support for `Boost.MP11`_.
|
||
|
||
.. _`Boost.MP11`: ../../../mp11/doc/html/mp11.html
|
||
.. |singular_cpp| replace:: singular.cpp
|
||
.. _singular_cpp: ../../test/singular.cpp
|
||
.. |optional_deduced_sfinae_cpp| replace:: optional_deduced_sfinae.cpp
|
||
.. _optional_deduced_sfinae_cpp: ../../test/optional_deduced_sfinae.cpp
|
||
.. |deduced_dep_pred_cpp| replace:: deduced_dependent_predicate.cpp
|
||
.. _deduced_dep_pred_cpp: ../../test/deduced_dependent_predicate.cpp
|
||
|
||
-----------------
|
||
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 parameter-enabled functions won't be removed
|
||
from the overload set based on their signatures. The |sfinae_cpp|_ and
|
||
|optional_deduced_sfinae|_ test programs demonstrate SFINAE support.
|
||
|
||
.. |sfinae_cpp| replace:: sfinae.cpp
|
||
.. _sfinae_cpp: ../../test/sfinae.cpp
|
||
.. |optional_deduced_sfinae| replace:: optional_deduced_sfinae.cpp
|
||
.. _optional_deduced_sfinae: ../../test/optional_deduced_sfinae.cpp
|
||
|
||
---------------------------
|
||
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;
|
||
}
|
||
|
||
==============
|
||
Python Binding
|
||
==============
|
||
|
||
.. _python: python.html
|
||
|
||
Follow `this link`__ for documentation on how to expose
|
||
Boost.Parameter-enabled functions to Python with `Boost.Python`_.
|
||
|
||
__ ../../../parameter_python/doc/html/index.html
|
||
|
||
=========
|
||
Reference
|
||
=========
|
||
|
||
.. _reference: reference.html
|
||
|
||
Follow `this link`__ to the Boost.Parameter reference documentation.
|
||
|
||
__ reference.html
|
||
|
||
========
|
||
Glossary
|
||
========
|
||
|
||
.. _arguments:
|
||
|
||
-------------------------------
|
||
Argument (or “actual argument”)
|
||
-------------------------------
|
||
|
||
the value actually passed to a function or class template.
|
||
|
||
.. _parameter:
|
||
|
||
---------------------------------
|
||
Parameter (or “formal parameter”)
|
||
---------------------------------
|
||
|
||
the name used to refer to an argument within a function or class
|
||
template. For example, the value of ``f``'s *parameter* ``x`` is given by the
|
||
*argument* ``3``:
|
||
|
||
.. parsed-literal::
|
||
|
||
int f(int x) { return x + 1; }
|
||
int y = f(3);
|
||
|
||
================
|
||
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.
|
||
|
||
.. [#ConceptsTS] This is a major motivation behind `C++20 constraints`_.
|
||
|
||
.. _`C++20 constraints`: http://en.cppreference.com/w/cpp/language/constraints
|
||
|
||
.. .. [#bind] The Lambda library is known not to work on `some
|
||
.. less-conformant compilers`__. When using one of those you could
|
||
.. use `Boost.Bind`_ to generate the function object\:\:
|
||
|
||
.. boost\:\:bind(std\:\:plus<std\:\:string>(),s1,s2)
|
||
|
||
.. [#is_keyword_expression] Here we're assuming there's a predicate
|
||
metafunction ``is_keyword_expression`` that can be used to identify
|
||
models of Boost.Python's KeywordExpression concept.
|
||
|
||
.. .. __ http://www.boost.org/regression/release/user/lambda.html
|
||
.. _Boost.Bind: ../../../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;
|
||
|
||
This technique for avoiding unintentional argument-dependent lookup is due
|
||
to Herb Sutter.
|
||
|
||
.. [#sfinae] This capability depends on your compiler's support for
|
||
SFINAE. **SFINAE**: **S**\ ubstitution **F**\ ailure **I**\ s **N**\ ot
|
||
**A**\ n **E**\ rror. 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, we can decide whether or not an overload is
|
||
considered during overload resolution. The technique is formalized in the
|
||
|enable_if|_ utility. Most recent compilers support SFINAE; on compilers
|
||
that don't support it, the Boost config library will ``#define`` the
|
||
symbol ``BOOST_NO_SFINAE``. See
|
||
http://www.semantics.org/once_weakly/w02_SFINAE.pdf for more information
|
||
on SFINAE.
|
||
|
||
.. |enable_if| replace:: ``enable_if``
|
||
.. _enable_if: ../../../core/doc/html/core/enable_if.html
|
||
|
||
|