⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 index.rst

📁 C++的一个好库。。。现在很流行
💻 RST
📖 第 1 页 / 共 3 页
字号:
+++++++++++++++++++++++++++++++++++++++++++++++++
 The Boost Parameter Library 
+++++++++++++++++++++++++++++++++++++++++++++++++

|(logo)|__

.. |(logo)| image:: ../../../../boost.png
   :alt: Boost

__ ../../../../index.htm

-------------------------------------

:Abstract: Use this library to write functions that accept
  arguments by name:

  .. parsed-literal::

    new_window("alert", **width=10**, **titlebar=false**);

  Since named arguments can be passed in any order, they are
  especially useful when a function has more than one parameter
  with a useful default value.

-------------------------------------

:Authors:       David Abrahams, Daniel Wallin
:Contact:       dave@boost-consulting.com, dalwan01@student.umu.se
:Organization:  `Boost Consulting`_
:Date:          $Date: 2005/07/18 20:34:31 $

:Copyright:     Copyright David Abrahams, Daniel Wallin
                2005. Distributed under the Boost Software License,
                Version 1.0. (See accompanying file LICENSE_1_0.txt
                or copy at http://www.boost.org/LICENSE_1_0.txt)

.. _`Boost Consulting`: http://www.boost-consulting.com

.. _concepts: ../../../more/generic_programming.html#concept

-------------------------------------

.. contents:: **Table of Contents**

.. role:: concept
   :class: concept

.. role:: vellipsis
   :class: vellipsis

.. section-numbering::

-------------------------------------

==============
 Introduction
==============

In C++, arguments are normally given meaning by their positions
with respect to a parameter list.  That protocol is fine when there
is at most one parameter with a default value, but when there are
even a few useful defaults, the positional interface becomes
burdensome:

* Since an argument's meaning is given by its position, we have to
  choose an (often arbitrary) order for parameters with default
  values, making some combinations of defaults unusable:

  .. parsed-literal::

    window* new_window(
       char const* name, 
       **int border_width = default_border_width,**
       bool movable = true,
       bool initially_visible = true
       );

    const bool movability = false;
    window* w = new_window("alert box", movability);

  In the example above we wanted to make an unmoveable window
  with a default ``border_width``, but instead we got a moveable
  window with a ``border_width`` of zero.  To get the desired
  effect, we'd need to write:

  .. parsed-literal::

    window* w = new_window(
       "alert box", **default_border_width**, movability);


* It can become difficult for readers to understand the meaning of
  arguments at the call site::

    window* w = new_window("alert", 1, true, false);

  Is this window moveable and initially invisible, or unmoveable
  and initially visible?  The reader needs to remember the order
  of arguments to be sure.  

* The author of the call may not remember the order of the
  arguments either, leading to hard-to-find bugs.

This library addresses the problems outlined above by associating
each parameter with a keyword object.  Now users can identify
arguments by keyword, rather than by position:

.. parsed-literal::

  window* w = new_window("alert box", **movable=**\ false); // OK!

.. I'm inclined to leave this part out.  In particular, the 2nd
   point is kinda lame because even with the library, we need to
   introduce overloads -- dwa:

   C++ has two other limitations, with respect to default arguments,
   that are unrelated to its positional interface:

   * Default values cannot depend on the values of other function
     parameters:

     .. parsed-literal::

       // Can we make resize windows to a square shape by default?
       void resize(
         window* w,
         int **width**, 
         int height **= width** // nope, error!
       );

   * Default values in function templates are useless for any
     argument whose type should be deduced when the argument is
     supplied explicitly::

        template <class T> 
        void f(T x = 0);

        f(3.14) // ok: x supplied explicitly; T is double
        f();    // error: can't deduce T from default argument 0!

   As a side effect of using the Boost Parameter library, you may find
   that you circumvent both of these limitations quite naturally.

==========
 Tutorial
==========

In this section we'll show how the Parameter library can be used to
build an expressive interface to the `Boost Graph library`__\ 's
|dfs|_ algorithm. [#old_interface]_ After laying some groundwork
and describing the algorithm's abstract interface, we'll show you
how to build a basic implementation with keyword support.  Then
we'll add support for default arguments and we'll gradually refine the
implementation with syntax improvements.  Finally we'll show how to
streamline the implementation of named parameter interfaces,
improve their participation in overload resolution, and optimize
their runtime efficiency.

__ ../../../graph/index.html

.. _dfs: ../../../graph/doc/depth_first_search.html

.. |dfs| replace:: ``depth_first_search``


Headers And Namespaces
======================

Most components of the Parameter library are declared in a
header named for the component.  For example, ::

  #include <boost/parameter/keyword.hpp>

will ensure ``boost::parameter::keyword`` is known to the
compiler.  There is also a combined header,
``boost/parameter.hpp``, that includes most of the library's
components.  For the the rest of this tutorial, unless we say
otherwise, you can use the rule above to figure out which header
to ``#include`` to access any given component of the library.

Also, the examples below will also be written as if the
namespace alias ::

  namespace parameter = boost::parameter;

has been declared: we'll write ``parameter::xxx`` instead of
``boost::parameter::xxx``.

The Abstract Interface to |dfs|
===============================

The Graph library's |dfs| algorithm is a generic function accepting
from one to four arguments by reference.  If all arguments were
required, its signature might be as follows::

   template <
       class Graph, class DFSVisitor, class Index, class ColorMap
   >
   void depth_first_search(
     , Graph const& graph 
     , DFSVisitor visitor
     , typename graph_traits<g>::vertex_descriptor root_vertex
     , IndexMap index_map
     , ColorMap& color);

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 Name | Dataflow | Default Value (if any)           |
  +================+==========+==================================+
  |``graph``       | in       |none - this argument is required. |
  +----------------+----------+----------------------------------+
  |``visitor``     | in       |``boost::dfs_visitor<>()``        |
  +----------------+----------+----------------------------------+
  |``root_vertex`` | in       |``*vertices(graph).first``        |
  +----------------+----------+----------------------------------+
  |``index_map``   | in       |``get(boost::vertex_index,graph)``|
  +----------------+----------+----------------------------------+
  |``color_map``   | out      |an ``iterator_property_map``      |
  |                |          |created from a ``std::vector`` of |
  |                |          |``default_color_type`` of size    |
  |                |          |``num_vertices(graph)`` and using |
  |                |          |``index_map`` for the index map.  |
  +----------------+----------+----------------------------------+

Don't be intimidated by the complex default values.  For the
purposes of this exercise, you don't need to understand what they
mean. Also, we'll show you how the default for ``color_map`` is
computed later in the tutorial; trust us when we say that the
complexity of its default will become valuable.

Defining the Keywords
=====================

The point of this exercise is to make it possible to call
``depth_first_search`` with keyword arguments, leaving out any
arguments for which the default is appropriate:

.. parsed-literal::

  graphs::depth_first_search(g, **color_map = my_color_map**);

To make that syntax legal, there needs to be an object called
``color_map`` with an assignment operator that can accept a
``my_color_map`` argument.  In this step we'll create one such
**keyword object** for each parameter.  Each keyword object will be
identified by a unique **keyword tag type**.  

We're going to define our interface in namespace ``graphs``.  Since
users need access to the keyword objects, but not the tag types,
we'll define the keyword objects so they're acceessible through
``graphs``, and we'll hide the tag types away in a tested
namespace, ``graphs::tag``.  The library provides a convenient
macro for that purpose (MSVC6.x users see this note__)::

  #include <boost/parameter/keyword.hpp>

  namespace graphs
  {
    BOOST_PARAMETER_KEYWORD(tag, graph)    // Note: no semicolon
    BOOST_PARAMETER_KEYWORD(tag, visitor)
    BOOST_PARAMETER_KEYWORD(tag, root_vertex)
    BOOST_PARAMETER_KEYWORD(tag, index_map)
    BOOST_PARAMETER_KEYWORD(tag, color_map)
  }

__ `Compiler Can't See References In Unnamed Namespace`_

The declaration of the ``visitor`` keyword you see here is
equivalent to::

  namespace graphs 
  {
    namespace tag { struct visitor; }
    namespace { 
      boost::parameter::keyword<tag::visitor>& visitor
      = boost::parameter::keyword<tag::visitor>::get();
    }
  }

This “fancy dance” involving the unnamed namespace and references
is all done to avoid violating the One Definition Rule (ODR)
[#odr]_ when the named parameter interface is used by function
templates that are instantiated in multiple translation
units.

Defining the Implementation Function
====================================

Next we can write the skeleton of the function that implements
the core of ``depth_first_search``::

  namespace graphs { namespace core
  {
    template <class ArgumentPack>
    void depth_first_search(ArgumentPack const& args)
    {
        // algorithm implementation goes here
    }
  }}

.. |ArgumentPack| replace:: :concept:`ArgumentPack`

``core::depth_first_search`` has an |ArgumentPack|
parameter: a bundle of references to the arguments that the caller
passes to the algorithm, tagged with their keywords.  To extract
each parameter, just pass its keyword object to the
|ArgumentPack|\ 's subscript operator.  Just to get a feel for how
things work, let's add some temporary code to print the arguments:

.. parsed-literal::

  namespace graphs { namespace core
  {
    template <class ArgumentPack>
    void depth_first_search(ArgumentPack const& args)
    {
        std::cout << "graph:\\t" << **args[graph]** << std::endl;
        std::cout << "visitor:\\t" << **args[visitor]** << std::endl;
        std::cout << "root_vertex:\\t" << **args[root_vertex]** << std::endl;
        std::cout << "index_map:\\t" << **args[index_map]** << std::endl;
        std::cout << "color_map:\\t" << **args[color_map]** << std::endl;
    }
  }} // graphs::core

It's unlikely that many of the arguments the caller will eventually
pass to ``depth_first_search`` can be printed, but for now the code
above will give us something to experiment with.  To see the
keywords in action, we can write a little test driver:

.. parsed-literal::

  int main()
  {
      using namespace graphs;

      core::depth_first_search(**(**
        graph = 'G', visitor = 2, root_vertex = 3.5, 
        index_map = "hello, world", color_map = false\ **)**);
  }

An overloaded comma operator (``operator,``) combines the results
of assigning to each keyword object into a single |ArgumentPack|
object that gets passed on to ``core::depth_first_search``.  The
extra set of parentheses you see in the example above are required:
without them, each assignment would be interpreted as a separate
function argument and the comma operator wouldn't take effect.
We'll show you how to get rid of the extra parentheses later in
this tutorial.

Of course, we can pass the arguments in any order::

  int main()
  {
      using namespace graphs;

      core::depth_first_search((
        root_vertex = 3.5, graph = 'G', color_map = false, 
        index_map = "hello, world", visitor = 2));
  }

either of the two programs above will print::

  graph:       G
  visitor:     2
  root_vertex: 3.5
  index_map:   hello, world
  color_map:   false

Adding Defaults
===============

Currently, all the arguments to ``depth_first_search`` are
required.  If any parameter can't be found, there will be a
compilation error where we try to extract it from the
|ArgumentPack| using the subscript operator.  To make it
legal to omit an argument we need to give it a default value.

Syntax
------

We can make any of the parameters optional by following its keyword
with the ``|`` operator and the parameter's default value within
the square brackets.  In the following example, we've given
``root_vertex`` a default of ``42`` and ``color_map`` a default of
``"hello, world"``.

.. parsed-literal::

  namespace graphs { namespace core
  {
    template <class ArgumentPack>
    void depth_first_search(ArgumentPack const& args)
    {
        std::cout << "graph:\\t" << args[graph] << std::endl;
        std::cout << "visitor:\\t" << args[visitor] << std::endl;
        std::cout << "root_vertex:\\t" << args[root_vertex\ **|42**\ ] << std::endl;
        std::cout << "index_map:\\t" << args[index_map] << std::endl;
        std::cout << "color_map:\\t" << args[color_map\ **|"hello, world"**\ ] << std::endl;
    }
  }} // graphs::core

Now we can invoke the function without supplying ``color_map`` or
``root_vertex``::

  core::depth_first_search((
    graph = 'G', index_map = "index", visitor = 6));

The call above would print::

  graph:       G
  visitor:     6
  root_vertex: 42
  index_map:   index
  color_map:   hello, world

.. Important::

   The index expression ``args[…]`` always yields a *reference*
   that is bound either to the actual argument passed by the caller

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -