From bf25a637c86a578a2d1cc580528782f30769e62a Mon Sep 17 00:00:00 2001 From: nobody Date: Tue, 21 Mar 2006 02:26:31 +0000 Subject: [PATCH 01/58] This commit was manufactured by cvs2svn to create branch 'RC_1_34_0'. [SVN r33417] From 6695f76c5f57a070b89d31d29791a66546e2a56c Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Thu, 13 Apr 2006 20:12:20 +0000 Subject: [PATCH 02/58] [merge from head] Allow keywords to be copyable and default constructable, to facilitate use of keywords outside of Boost.Parameter. [SVN r33691] --- include/boost/parameter/keyword.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/boost/parameter/keyword.hpp b/include/boost/parameter/keyword.hpp index fa556e5..9011aa8 100755 --- a/include/boost/parameter/keyword.hpp +++ b/include/boost/parameter/keyword.hpp @@ -9,7 +9,6 @@ #include #include #include -#include namespace boost { namespace parameter { @@ -29,7 +28,7 @@ namespace boost { namespace parameter { // f(rate = 1, skew = 2.4); // template -struct keyword : noncopyable +struct keyword { template typename aux::tag::type const @@ -98,9 +97,6 @@ struct keyword : noncopyable static keyword result; return result; } - - private: - keyword() {} }; // Reduces boilerplate required to declare and initialize keywords From e2b452c1f4ed58298c86c1747af6dab78ae9e91b Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 12 Jun 2006 20:00:14 +0000 Subject: [PATCH 03/58] merged from trunk [SVN r34290] --- include/boost/parameter/aux_/maybe.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/parameter/aux_/maybe.hpp b/include/boost/parameter/aux_/maybe.hpp index f74064b..ddb06e0 100755 --- a/include/boost/parameter/aux_/maybe.hpp +++ b/include/boost/parameter/aux_/maybe.hpp @@ -24,7 +24,11 @@ struct maybe : maybe_base is_reference , T , typename add_reference< +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + T const +# else typename add_const::type +# endif >::type >::type reference; From ca120a3f048e4b6db5be3fd7f0c378a3371df20a Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 24 Jul 2006 14:38:01 +0000 Subject: [PATCH 04/58] merged from trunk [SVN r34696] --- .../boost/parameter/aux_/tagged_argument.hpp | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/include/boost/parameter/aux_/tagged_argument.hpp b/include/boost/parameter/aux_/tagged_argument.hpp index cdde3f8..d09e8ab 100755 --- a/include/boost/parameter/aux_/tagged_argument.hpp +++ b/include/boost/parameter/aux_/tagged_argument.hpp @@ -21,11 +21,13 @@ namespace boost { namespace parameter { namespace aux { struct empty_arg_list; struct arg_list_tag; +struct tagged_argument_base {}; + // Holds a reference to an argument of type Arg associated with // keyword Keyword template -struct tagged_argument +struct tagged_argument : tagged_argument_base { typedef Keyword key_type; typedef Arg value_type; @@ -163,23 +165,12 @@ struct tagged_argument typedef arg_list_tag tag; // For dispatching to sequence intrinsics }; -template -char is_tagged_argument_check(tagged_argument const*); -char(&is_tagged_argument_check(...))[2]; - // Defines a metafunction, is_tagged_argument, that identifies -// tagged_argument specializations. -// MAINTAINER NOTE: Not using BOOST_DETAIL_IS_XXX_DEF here because -// we need to return true for tagged_argument const. +// tagged_argument specializations and their derived classes. template struct is_tagged_argument_aux -{ - enum { value = - sizeof(is_tagged_argument_check((T*)0)) == 1 - }; - - typedef mpl::bool_ type; -}; + : is_convertible +{}; template struct is_tagged_argument From 00bbfbb20c60b126997fd2b15a478d263d134d58 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Thu, 27 Jul 2006 11:48:49 +0000 Subject: [PATCH 05/58] boost guidelines (mainly from inspect tool: tabs, license reference text, etc.); more to do... [SVN r34753] --- test/basics.cpp | 2 +- test/basics.hpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/basics.cpp b/test/basics.cpp index da8b7eb..d4a1279 100755 --- a/test/basics.cpp +++ b/test/basics.cpp @@ -20,7 +20,7 @@ namespace test typename boost::parameter::lazy_binding::type extract_value(Params const& p, F const& f) { - typename boost::parameter::lazy_binding< + typename ::boost::parameter::lazy_binding< Params, tag::value, F >::type v = p[value || f ]; return v; diff --git a/test/basics.hpp b/test/basics.hpp index 9407a1c..8a9223a 100755 --- a/test/basics.hpp +++ b/test/basics.hpp @@ -36,11 +36,15 @@ inline double value_default() return 666.222; } -template +/*template inline bool equal(T const& x, T const& y) { return x == y; -} +}*/ + +template +inline bool equal(T x, T y) { return x == y; } + inline bool equal(char const* s1, char const* s2) { From 49e928273da0464ff62a5b52d22197a8c2298546 Mon Sep 17 00:00:00 2001 From: nobody Date: Sun, 30 Jul 2006 21:33:23 +0000 Subject: [PATCH 06/58] This commit was manufactured by cvs2svn to create branch 'RC_1_34_0'. [SVN r34788] --- doc/html/python.html | 750 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 750 insertions(+) create mode 100644 doc/html/python.html diff --git a/doc/html/python.html b/doc/html/python.html new file mode 100644 index 0000000..6653394 --- /dev/null +++ b/doc/html/python.html @@ -0,0 +1,750 @@ + + + + + + +The Boost Parameter Library Python Binding Documentation + + + +
+

The Boost Parameter Library Python Binding Documentation

+ +

Boost

+ +++ + + + + + + + + + + + +
Authors:Daniel Wallin
Contact:dalwan01@student.umu.se
organization:Boost Consulting
date:$Date$
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)
+ +
+

Introduction

+

boost/parameter/python.hpp introduces a group of def_visitors that can +be used to easily expose Boost.Parameter-enabled member functions to Python with +Boost.Python. It also provides a function template def() that can be used +to expose Boost.Parameter-enabled free functions.

+

When binding a Boost.Parameter enabled function, the keyword tags +must be specified. Additionally, because Boost.Parameter enabled +functions are templates, the desired function signature must be +specified.

+

The keyword tags are specified as an MPL Sequence, using the +pointer qualifications described in KeywordsSpec below. The +signature is also specifid as an MPL sequence of parameter +types. Additionally, boost::parameter::python::function and +boost::parameter::python::def requires a class with forwarding +overloads. We will take a closer look at how this is done in the +tutorial section below.

+ + + + +
+
+

Tutorial

+

In this section we will outline the steps needed to bind a simple +Boost.Parameter-enabled member function to Python. Knowledge of the +Boost.Parameter macros are required to understand this section.

+

The class and member function we are interested in binding looks +like this:

+
+#include <boost/parameter/keyword.hpp>
+#include <boost/parameter/preprocessor.hpp>
+#include <boost/parameter/python.hpp>
+#include <boost/python.hpp>
+
+// First the keywords
+BOOST_PARAMETER_KEYWORD(tag, title)
+BOOST_PARAMETER_KEYWORD(tag, width)
+BOOST_PARAMETER_KEYWORD(tag, height)
+
+class window
+{
+public:
+    BOOST_PARAMETER_MEMBER_FUNCTION(
+      (void), open, tag,
+      (required (title, (std::string)))
+      (optional (width, (unsigned), 400)
+                (height, (unsigned), 400))
+    )
+    {
+        
+    }
+};
+
+ + +

It defines a set of overloaded member functions called open with one +required parameter and two optional ones. To bind this member function to +Python we use the binding utility boost::parameter::python::function. +boost::parameter::python::function is a def_visitor that we'll instantiate +and pass to boost::python::class_::def().

+

To use boost::parameter::python::function we first need to define +a class with forwarding overloads.

+
+struct open_fwd
+{
+    template <class A0, class A1, class A2>
+    void operator()(
+        boost::type<void>, window& self, A0 const& a0, A1 const& a1, A2 const& a2
+    )
+    {
+        self.open(a0, a1, a2);
+    }
+};
+
+

The first parameter, boost::type<void>, tells the forwarding overload +what the return type should be. In this case we know that it's always void +but in some cases, when we are exporting several specializations of a +Boost.Parameter-enabled template, we need to use that parameter to +deduce the return type.

+

window::open() takes a total of 3 parameters, so the forwarding function +needs to take three parameters as well.

+
+

Note

+

We only need one overload in the forwarding class, despite the +fact that there are two optional parameters. There are special +circumstances when several overload are needed; see +special keywords.

+
+

Next we'll define the module and export the class:

+
+BOOST_PYTHON_MODULE(my_module)
+{
+    using namespace boost::python;
+    namespace py = boost::parameter::python;
+    namespace mpl = boost::mpl;
+
+    class_<window>("window")
+        .def(
+            "open", py::function<
+                open_fwd
+              , mpl::vector<
+                    void
+                  , tag::title(std::string)
+                  , tag::width*(unsigned)
+                  , tag::height*(unsigned)
+                >
+            >()
+        );
+}
+
+ + + + +

py::function is passed three parameters. The first one is the class +with forwarding overloads that we defined earlier. The second one is +an MPL Sequence with the keyword tag types for the function. The +pointer syntax means that the parameter is optional, so in this case +width and height are optional parameters. The third parameter +is an MPL Sequence with the desired function signature. The return type comes first, and +then the parameter types:

+
+mpl::vector<void,        std::string, unsigned, unsigned>
+            return type  title        width     height
+
+ +

That's it! This class can now be used in Python with the expected syntax:

+
+>>> w = my_module.window()
+>>> w.open(title = "foo", height = 20)
+
+ + + + +
+
+
+

concept KeywordsSpec

+

A KeywordsSpec is an MPL sequence where each element is either:

+
    +
  • A required keyword of the form K
  • +
  • or, an optional keyword of the form K*
  • +
  • or, a special keyword of the form K**
  • +
+

where K is a keyword tag type, as used in a specialization +of boost::parameter::keyword.

+

The arity range of a KeywordsSpec is defined as the closed +range:

+
+[ mpl::size<S> - number of special keyword tags in S , mpl::size<S> ]
+
+ +

For example, the arity range of mpl::vector2<x,y> is [2,2], the arity range of +mpl::vector2<x,y*> is [2,2] and the arity range of mpl::vector2<x,y**> is [1,2].

+ +
+
+

special keywords

+

Sometimes it is desirable to have a default value for a parameter that differ +in type from the parameter. This technique is useful for doing simple tag-dispatching +based on the presence of a parameter. An example of this is given in the Boost.Parameter +docs. The example uses a different technique, but could also have been written like this:

+
+namespace core
+{
+  template <class ArgumentPack>
+  void dfs_dispatch(ArgumentPack const& args, mpl::false_)
+  {
+      …compute and use default color map…
+  }
+
+  template <class ArgumentPack, class ColorMap>
+  void dfs_dispatch(ArgumentPack const& args, ColorMap colormap)
+  {
+      …use colormap…
+  }
+}
+
+template <class ArgumentPack>
+void depth_first_search(ArgumentPack const& args)
+{
+    core::dfs_dispatch(args, args[color | mpl::false_()]);
+}
+
+ + + + + +

In the above example the type of the default for color is mpl::false_, a +type that is distinct from any color map that the user might supply.

+

When binding the case outlined above, the default type for color will not +be convertible to the parameter type. Therefore we need to tag the color +keyword as a special keyword. By doing this we tell the binding functions +that it needs to generate two overloads, one with the color parameter +present and one without. Had there been two special keywords, four +overloads would need to be generated. The number of generated overloads is +equal to 2^N, where N is the number of special keywords.

+
+
+
+

class template init

+

Defines a named parameter enabled constructor.

+
+template <class Keywords, class Signature>
+struct init : python::def_visitor<init<Keywords, Signature> >
+{
+    template <class Class>
+    void def(Class& class_);
+};
+
+ +
+

init requirements

+
    +
  • Keywords is a model of KeywordsSpec.

    +
  • +
  • Signature is an MPL sequence of parameter types, +in the order dictated by Keywords.

    +
  • +
  • For every N in [U,V], where [U,V] is the arity +range of Keywords, Class must support these +expressions:

    + +++++ + + + + + + + + + + + + +

    Expression

    +

    Return type

    +

    Requirements

    +

    Class(a0, ..., aN)

    +

    -

    +

    a0..aN are tagged arguments.

    +
    +
  • +
+ + + +
+
+

Example

+
+#include <boost/parameter/keyword.hpp>
+#include <boost/parameter/preprocessor.hpp>
+#include <boost/parameter/python.hpp>
+#include <boost/python.hpp>
+#include <boost/mpl/vector.hpp>
+
+BOOST_PARAMETER_KEYWORD(tag, x)
+BOOST_PARAMETER_KEYWORD(tag, y)
+
+struct base
+{
+    template <class ArgumentPack>
+    base(ArgumentPack const& args)
+    {
+        …use args…
+    }
+};
+
+class X : base
+{
+public:
+    BOOST_PARAMETER_CONSTRUCTOR(X, (base), tag,
+        (required (x, *))
+        (optional (y, *))
+    )
+};
+
+BOOST_PYTHON_MODULE(module name)
+{
+    using namespace boost::python;
+    namespace py = boost::parameter::python;
+    namespace mpl = boost::mpl;
+
+    class_<X>("X", no_init)
+        .def(
+            py::init<
+                mpl::vector<tag::x(int), tag::y*(int)>
+            >()
+        );
+}
+
+ + + + + +
+
+
+
+

class template call

+

Defines a __call__ operator, mapped to operator() in C++.

+
+template <class Keywords, class Signature>
+struct call : python::def_visitor<call<Keywords, Signature> >
+{
+    template <class Class>
+    void def(Class& class_);
+};
+
+ +
+

call requirements

+
    +
  • Keywords is a model of KeywordsSpec.

    +
  • +
  • Signature is an MPL sequence with the types of the keyword parameters, +in the order dictated by Keywords, and the return type prepended.

    +
  • +
  • Class must support these expressions, where c is an instance of Class:

    + +++++ + + + + + + + + + + + + +

    Expression

    +

    Return type

    +

    Requirements

    +

    c(a0, ..., aN)

    +

    Convertible to R

    +

    a0..aN are tagged arguments.

    +
    +

    For every N in [U,V], where [U,V] is the arity range of Keywords.

    +
  • +
+
+
+

Example

+
+#include <boost/parameter/keyword.hpp>
+#include <boost/parameter/preprocessor.hpp>
+#include <boost/parameter/python.hpp>
+#include <boost/python.hpp>
+#include <boost/mpl/vector.hpp>
+
+BOOST_PARAMETER_KEYWORD(tag, x)
+BOOST_PARAMETER_KEYWORD(tag, y)
+
+namespace parameter = boost::parameter;
+
+typedef parameter::parameters<
+    parameter::required<tag::x>
+  , parameter::optional<tag::y>
+> call_parameters;
+
+class X
+{
+public:
+    template <class ArgumentPack>
+    int call_impl(ArgumentPack const& args)
+    {
+        …use args…
+    }
+
+    template <class A0>
+    int operator()(A0 const& a0)
+    {
+        return call_impl(call_parameters()(a0));
+    }
+
+    template <class A0, class A1>
+    int operator()(A0 const& a0, A1 const& a1)
+    {
+        return call_impl(call_parameters()(a0,a1));
+    }
+};
+
+BOOST_PYTHON_MODULE(module name)
+{
+    using namespace boost::python;
+    namespace py = parameter::python;
+    namespace mpl = boost::mpl;
+
+    class_<X>("X")
+        .def(
+            py::call<
+                mpl::vector<int, tag::x(int), tag::y*(int)>
+            >()
+        );
+}
+
+ + + +
+
+
+
+

class template function

+

Defines a named parameter enabled member function.

+
+template <class Fwd, class Keywords, class Signature>
+struct function : python::def_visitor<function<Fwd, Keywords, Signature> >
+{
+    template <class Class, class Options>
+    void def(Class& class_, char const* name, Options const& options);
+};
+
+ +
+

function requirements

+
    +
  • Keywords is a model of KeywordsSpec.

    +
  • +
  • Signature is an MPL sequence with the types of the keyword parameters, +in the order dictated by Keywords, and the return type prepended.

    +
  • +
  • An instance of Fwd must support this expression:

    + +++++ + + + + + + + + + + + + +

    Expression

    +

    Return type

    +

    Requirements

    +

    fwd(boost::type<R>(), self, a0, …, aN)

    +

    Convertible to R

    +

    self is a reference to the object on which +the function should be invoked. a0``…``aN +are tagged arguments.

    +
    +

    For every N in [U,V], where [U,V] is the arity range of Keywords.

    +
  • +
+
+
+

Example

+

This example exports a member function f(int x, int y = …) to Python. +The KeywordsSpec mpl::vector2<tag::x, tag::y*> has an arity range +of [2,2], so we only need one forwarding overload.

+
+#include <boost/parameter/keyword.hpp>
+#include <boost/parameter/preprocessor.hpp>
+#include <boost/parameter/python.hpp>
+#include <boost/python.hpp>
+#include <boost/mpl/vector.hpp>
+
+BOOST_PARAMETER_KEYWORD(tag, x)
+BOOST_PARAMETER_KEYWORD(tag, y)
+
+class X
+{
+public:
+    BOOST_PARAMETER_MEMBER_FUNCTION((void), f, tag,
+        (required (x, *))
+        (optional (y, *, 1))
+    )
+    {
+        
+    }
+};
+
+struct f_fwd
+{
+    template <class A0, class A1>
+    void operator()(boost::type<void>, X& self, A0 const& a0, A1 const& a1)
+    {
+        self.f(a0, a1);
+    }
+};
+
+BOOST_PYTHON_MODULE(module name)
+{
+    using namespace boost::python;
+    namespace py = boost::parameter::python;
+    namespace mpl = boost::mpl;
+
+    class_<X>("X")
+        .def("f",
+            py::function<
+                f_fwd
+              , mpl::vector<void, tag::x(int), tag::y*(int)>
+            >()
+        );
+}
+
+ + + +
+
+
+
+

function template def

+

Defines a named parameter enabled free function in the current Python scope.

+
+template <class Fwd, class Keywords, class Signature>
+void def(char const* name);
+
+ +
+

def requirements

+
    +
  • Keywords is a model of KeywordsSpec.

    +
  • +
  • Signature is an MPL sequence of parameters types, +in the order dictated by Keywords, with the return type +prepended.

    +
  • +
  • An instance of Fwd must support this expression:

    + +++++ + + + + + + + + + + + + +

    Expression

    +

    Return type

    +

    Requirements

    +

    fwd(boost::type<R>(), a0, …, aN)

    +

    Convertible to R

    +

    a0``…``aN are tagged arguments.

    +
    +

    For every N in [U,V], where [U,V] is the arity range of Keywords.

    +
  • +
+
+
+

Example

+

This example exports a function f(int x, int y = …) to Python. +The KeywordsSpec mpl::vector2<tag::x, tag::y*> has an arity range +of [2,2], so we only need one forwarding overload.

+
+BOOST_PARAMETER_FUNCTION((void), f, tag,
+    (required (x, *))
+    (optional (y, *, 1))
+)
+{
+    
+}
+
+struct f_fwd
+{
+    template <class A0, class A1>
+    void operator()(boost::type<void>, A0 const& a0, A1 const& a1)
+    {
+        f(a0, a1);
+    }
+};
+
+BOOST_PYTHON_MODULE(…)
+{
+    def<
+        f_fwd
+      , mpl::vector<
+            void, tag::x(int), tag::y*(int)
+        >
+    >("f");
+}
+
+ + +
+
+
+

Portability

+

The Boost.Parameter Python binding library requires partial template specialization.

+
+
+ + + From cf5d2c46f57bd1f15c829785fcbd9c86b3e9c30d Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 2 Aug 2006 16:16:36 +0000 Subject: [PATCH 07/58] Workarounds for Borland [SVN r34805] --- include/boost/parameter/preprocessor.hpp | 52 +++++++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/include/boost/parameter/preprocessor.hpp b/include/boost/parameter/preprocessor.hpp index 5e4bb1a..04f03ba 100755 --- a/include/boost/parameter/preprocessor.hpp +++ b/include/boost/parameter/preprocessor.hpp @@ -98,6 +98,42 @@ struct unwrap_type # define BOOST_PARAMETER_FUNCTION_WRAP_TYPE(x) void(*) x +# elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +template +struct unwrap_predicate; + +// Wildcard case +template <> +struct unwrap_predicate +{ + typedef mpl::always type; +}; + +// Convertible to +template +struct unwrap_predicate +{ + typedef T type; +}; + +template +struct unwrap_predicate +{ + typedef is_convertible type; +}; + +template +struct unwrap_type; + +template +struct unwrap_type +{ + typedef T type; +}; + +# define BOOST_PARAMETER_FUNCTION_WRAP_TYPE(x) void(*) x + # else template @@ -338,7 +374,19 @@ struct argument_pack /**/ // Builds boost::parameter::parameters<> specialization -# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ + BOOST_PP_COMMA_IF(i) \ + boost::parameter::BOOST_PARAMETER_FN_ARG_QUALIFIER(elem)< \ + tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ + BOOST_PARAMETER_FN_ARG_NAME(elem) \ + ) \ + , typename boost::parameter::aux::unwrap_predicate< \ + void (*)BOOST_PARAMETER_FN_ARG_PRED(elem) \ + , BoostParameterDummyTemplateArg \ + >::type \ + > +# elif !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) # define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ BOOST_PP_COMMA_IF(i) \ boost::parameter::BOOST_PARAMETER_FN_ARG_QUALIFIER(elem)< \ @@ -386,7 +434,7 @@ struct argument_pack template \ struct apply \ { \ - template \ + template \ struct binding \ : boost::parameter::binding \ {}; \ From 6729c3850476cdceb66fe24f209138e24d32da70 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 2 Aug 2006 19:07:09 +0000 Subject: [PATCH 08/58] Borland workaround [SVN r34808] --- test/basics.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/basics.cpp b/test/basics.cpp index d4a1279..8276788 100755 --- a/test/basics.cpp +++ b/test/basics.cpp @@ -20,7 +20,10 @@ namespace test typename boost::parameter::lazy_binding::type extract_value(Params const& p, F const& f) { - typename ::boost::parameter::lazy_binding< +#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + typename +#endif + ::boost::parameter::lazy_binding< Params, tag::value, F >::type v = p[value || f ]; return v; From 1f8f44b26c0d0fdf2a604d237aeb8832b57852e0 Mon Sep 17 00:00:00 2001 From: Daniel Wallin Date: Wed, 16 Aug 2006 22:30:07 +0000 Subject: [PATCH 09/58] Merged changes from HEAD to RC_1_34_0. [SVN r34898] --- test/preprocessor.cpp | 179 ++++++++++++++++++++++++++++++++++++++++-- test/python.cpp | 89 +++++++++++++++++++-- test/python.py | 8 +- 3 files changed, 262 insertions(+), 14 deletions(-) diff --git a/test/preprocessor.cpp b/test/preprocessor.cpp index c0f8018..3ca752c 100755 --- a/test/preprocessor.cpp +++ b/test/preprocessor.cpp @@ -14,7 +14,7 @@ namespace test { -BOOST_PARAMETER_FUNCTION((int), f, tag, +BOOST_PARAMETER_BASIC_FUNCTION((int), f, tag, (required (tester, *) (name, *) @@ -40,7 +40,7 @@ BOOST_PARAMETER_FUNCTION((int), f, tag, return 1; } -BOOST_PARAMETER_FUNCTION((int), g, tag, +BOOST_PARAMETER_BASIC_FUNCTION((int), g, tag, (required (tester, *) (name, *) @@ -66,6 +66,52 @@ BOOST_PARAMETER_FUNCTION((int), g, tag, return 1; } +BOOST_PARAMETER_FUNCTION((int), h, tag, + (required + (tester, *) + (name, *) + ) + (optional + (value, *, 1.f) + (out(index), (int), 2) + ) +) +{ + BOOST_MPL_ASSERT((boost::is_same)); + + tester( + name + , value + , index + ); + + return 1; +} + +BOOST_PARAMETER_FUNCTION((int), h2, tag, + (required + (tester, *) + (name, *) + ) + (optional + (value, *, 1.f) + (out(index), (int), (int)value * 2) + ) +) +{ +# if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + BOOST_MPL_ASSERT((boost::is_same)); +# endif + + tester( + name + , value + , index + ); + + return 1; +} + struct base { template @@ -92,7 +138,7 @@ struct class_ : base ) ) - BOOST_PARAMETER_MEMBER_FUNCTION((int), f, tag, + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION((int), f, tag, (required (tester, *) (name, *) @@ -112,7 +158,7 @@ struct class_ : base return 1; } - BOOST_PARAMETER_CONST_MEMBER_FUNCTION((int), f, tag, + BOOST_PARAMETER_BASIC_CONST_MEMBER_FUNCTION((int), f, tag, (required (tester, *) (name, *) @@ -131,6 +177,52 @@ struct class_ : base return 1; } + + BOOST_PARAMETER_MEMBER_FUNCTION((int), f2, tag, + (required + (tester, *) + (name, *) + ) + (optional + (value, *, 1.f) + (index, *, 2) + ) + ) + { + tester(name, value, index); + return 1; + } + + BOOST_PARAMETER_CONST_MEMBER_FUNCTION((int), f2, tag, + (required + (tester, *) + (name, *) + ) + (optional + (value, *, 1.f) + (index, *, 2) + ) + ) + { + tester(name, value, index); + return 1; + } + + + BOOST_PARAMETER_MEMBER_FUNCTION((int), static f_static, tag, + (required + (tester, *) + (name, *) + ) + (optional + (value, *, 1.f) + (index, *, 2) + ) + ) + { + tester(name, value, index); + return 1; + } }; BOOST_PARAMETER_FUNCTION( @@ -158,6 +250,31 @@ sfinae(A0 const& a0) } #endif +BOOST_PARAMETER_FUNCTION( + (int), sfinae1, tag, + (required + (name, *(boost::is_convertible)) + ) +) +{ + return 1; +} + +#ifndef BOOST_NO_SFINAE +// On compilers that actually support SFINAE, add another overload +// that is an equally good match and can only be in the overload set +// when the others are not. This tests that the SFINAE is actually +// working. On all other compilers we're just checking that +// everything about SFINAE-enabled code will work, except of course +// the SFINAE. +template +typename boost::enable_if, int>::type +sfinae1(A0 const& a0) +{ + return 0; +} +#endif + } int main() @@ -190,6 +307,19 @@ int main() , 2 ); + h( + tester = values(S("foo"), 1.f, 2) + , name = S("foo") + , 1.f + , 2 + ); + + h2( + tester = values(S("foo"), 1.f, 2) + , name = S("foo") + , 1.f + ); + class_ x( tester = values(S("foo"), 1.f, 2) , S("foo"), test::index = 2 @@ -205,6 +335,16 @@ int main() , name = S("foo") ); + x.f2( + tester = values(S("foo"), 1.f, 2) + , S("foo") + ); + + x.f2( + tester = values(S("foo"), 1.f, 2) + , name = S("foo") + ); + class_ const& x_const = x; x_const.f( @@ -216,10 +356,39 @@ int main() tester = values(S("foo"), 1.f, 2) , name = S("foo") ); - + + x_const.f2( + tester = values(S("foo"), 1.f, 2) + , S("foo") + ); + + x_const.f2( + tester = values(S("foo"), 1.f, 2) + , name = S("foo") + ); + + x_const.f2( + tester = values(S("foo"), 1.f, 2) + , name = S("foo") + ); + + class_::f_static( + tester = values(S("foo"), 1.f, 2) + , S("foo") + ); + + class_::f_static( + tester = values(S("foo"), 1.f, 2) + , name = S("foo") + ); + #ifndef BOOST_NO_SFINAE assert(sfinae("foo") == 1); assert(sfinae(1) == 0); + + assert(sfinae1("foo") == 1); + assert(sfinae1(1) == 0); #endif + return 0; } diff --git a/test/python.cpp b/test/python.cpp index 3d9b5b1..584469d 100755 --- a/test/python.cpp +++ b/test/python.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace test { @@ -13,9 +14,32 @@ BOOST_PARAMETER_KEYWORD(tag, x) BOOST_PARAMETER_KEYWORD(tag, y) BOOST_PARAMETER_KEYWORD(tag, z) -struct X +struct Xbase { - BOOST_PARAMETER_MEMBER_FUNCTION((int), f, tag, + // We need the disable_if part for VC7.1/8.0. + template + Xbase( + Args const& args + , typename boost::disable_if< + boost::is_base_and_derived + >::type* = 0 + ) + : value(std::string(args[x | "foo"]) + args[y | "bar"]) + {} + + std::string value; +}; + +struct X : Xbase +{ + BOOST_PARAMETER_CONSTRUCTOR(X, (Xbase), tag, + (optional + (x, *) + (y, *) + ) + ) + + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION((int), f, tag, (required (x, *) (y, *) @@ -28,7 +52,7 @@ struct X return args[x] + args[y] + args[z | 0]; } - BOOST_PARAMETER_MEMBER_FUNCTION((std::string), g, tag, + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION((std::string), g, tag, (optional (x, *) (y, *) @@ -37,6 +61,19 @@ struct X { return std::string(args[x | "foo"]) + args[y | "bar"]; } + + BOOST_PARAMETER_MEMBER_FUNCTION((X&), h, tag, + (optional (x, *, "") (y, *, "")) + ) + { + return *this; + } + + template + X& operator()(A0 const& a0) + { + return *this; + } }; } // namespace test @@ -59,6 +96,15 @@ struct g_fwd } }; +struct h_fwd +{ + template + R operator()(boost::type, T& self, A0 const& a0, A1 const& a1) + { + return self.h(a0,a1); + } +}; + BOOST_PYTHON_MODULE(python_parameter) { namespace mpl = boost::mpl; @@ -66,21 +112,48 @@ BOOST_PYTHON_MODULE(python_parameter) using namespace boost::python; class_("X") + .def( + boost::parameter::python::init< + mpl::vector< + tag::x*(std::string), tag::y*(std::string) + > + >() + ) .def( "f" , boost::parameter::python::function< f_fwd - , mpl::vector3 - , mpl::vector4 + , mpl::vector< + int, tag::x(int), tag::y(int), tag::z*(int) + > >() ) .def( "g" , boost::parameter::python::function< g_fwd - , mpl::vector2 - , mpl::vector3 + , mpl::vector< + std::string, tag::x*(std::string), tag::y*(std::string) + > >() - ); + ) + .def( + "h" + , boost::parameter::python::function< + h_fwd + , mpl::vector< + X&, tag::x*(std::string), tag::y*(std::string) + > + >() + , return_arg<>() + ) + .def( + boost::parameter::python::call< + mpl::vector< + X&, tag::x(int) + > + >() [ return_arg<>() ] + ) + .def_readonly("value", &X::value); } diff --git a/test/python.py b/test/python.py index cd5540c..8bd2a56 100644 --- a/test/python.py +++ b/test/python.py @@ -1,6 +1,8 @@ ''' >>> from python_parameter import X ->>> x = X() +>>> x = X(y = 'baz') +>>> x.value +'foobaz' >>> x.f(1,2) 3 >>> x.f(1,2,3) @@ -17,6 +19,10 @@ 'bazbar' >>> x.g(y = "foo", x = "bar") 'barfoo' +>>> y = x.h(x = "bar", y = "foo") +>>> assert x == y +>>> y = x(0) +>>> assert x == y ''' def run(args = None): From bfc5811fdc6ad568bf8747dc1b5fe233bf25653c Mon Sep 17 00:00:00 2001 From: Daniel Wallin Date: Wed, 16 Aug 2006 22:34:35 +0000 Subject: [PATCH 10/58] Merged HEAD to RC_1_34_0. [SVN r34899] --- include/boost/parameter/aux_/arg_list.hpp | 2 +- .../parameter/aux_/parenthesized_type.hpp | 119 +++ .../parameter/aux_/preprocessor/flatten.hpp | 4 +- .../parameter/aux_/preprocessor/for_each.hpp | 1 + include/boost/parameter/parameters.hpp | 35 +- include/boost/parameter/preprocessor.hpp | 733 ++++++++++++------ include/boost/parameter/python.hpp | 159 +++- 7 files changed, 745 insertions(+), 308 deletions(-) create mode 100755 include/boost/parameter/aux_/parenthesized_type.hpp diff --git a/include/boost/parameter/aux_/arg_list.hpp b/include/boost/parameter/aux_/arg_list.hpp index fbd52bc..404bfd6 100755 --- a/include/boost/parameter/aux_/arg_list.hpp +++ b/include/boost/parameter/aux_/arg_list.hpp @@ -176,7 +176,7 @@ template struct arg_list : Next { typedef arg_list self; - typedef typename TaggedArg::key_type key_type; + typedef typename TaggedArg::key_type key_type; typedef typename is_maybe::type holds_maybe; diff --git a/include/boost/parameter/aux_/parenthesized_type.hpp b/include/boost/parameter/aux_/parenthesized_type.hpp new file mode 100755 index 0000000..c6ddd77 --- /dev/null +++ b/include/boost/parameter/aux_/parenthesized_type.hpp @@ -0,0 +1,119 @@ +// Copyright David Abrahams 2006. 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) +#ifndef BOOST_PARAMETER_AUX_PARENTHESIZED_TYPE_DWA2006414_HPP +# define BOOST_PARAMETER_AUX_PARENTHESIZED_TYPE_DWA2006414_HPP + +# include +# include + +namespace boost { namespace parameter { namespace aux { + +// A macro that takes a parenthesized C++ type name (T) and transforms +// it into an un-parenthesized type expression equivalent to T. +# define BOOST_PARAMETER_PARENTHESIZED_TYPE(x) \ + boost::parameter::aux::unaryfunptr_arg_type< void(*)x >::type + +// A metafunction that transforms void(*)(T) -> T +template +struct unaryfunptr_arg_type; + +# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + +template +struct unaryfunptr_arg_type +{ + typedef Arg type; +}; + +# else + +// Use the "native typeof" bugfeatures of older versions of MSVC to +// accomplish what we'd normally do with partial specialization. This +// capability was discovered by Igor Chesnokov. + +# if BOOST_WORKAROUND(BOOST_MSVC, != 1300) + +// This version applies to VC6.5 and VC7.1 (except that we can just +// use partial specialization for the latter in this case). + +// This gets used as a base class. +template +struct msvc_type_memory +{ + // A nullary metafunction that will yield the Value type "stored" + // at this Address. + struct storage; +}; + +template +struct msvc_store_type : msvc_type_memory
+{ + // VC++ somehow lets us define the base's nested storage + // metafunction here, where we have the Value type we'd like to + // "store" in it. Later we can come back to the base class and + // extract the "stored type." + typedef msvc_type_memory
location; + struct location::storage + { + typedef Value type; + }; +}; + +# else + +// This slightly more complicated version of the same thing is +// required for msvc-7.0 +template +struct msvc_type_memory +{ + template + struct storage_impl; + + typedef storage_impl storage; +}; + +template +struct msvc_store_type : msvc_type_memory
+{ + // Rather than supplying a definition for the base class' nested + // class, we specialize the base class' nested template + template<> + struct storage_impl + { + typedef Value type; + }; +}; + +# endif + +// Function template argument deduction does many of the same things +// as type matching during partial specialization, so we call a +// function template to "store" T into the type memory addressed by +// void(*)(T). +template +msvc_store_type +msvc_store_argument_type(void(*)(T)); + +template +struct unaryfunptr_arg_type +{ + // We don't want the function to be evaluated, just instantiated, + // so protect it inside of sizeof. + enum { dummy = sizeof(msvc_store_argument_type((FunctionPointer)0)) }; + + // Now pull the type out of the instantiated base class + typedef typename msvc_type_memory::storage::type type; +}; + +# endif + +template <> +struct unaryfunptr_arg_type +{ + typedef void type; +}; + +}}} // namespace boost::parameter::aux + +#endif // BOOST_PARAMETER_AUX_PARENTHESIZED_TYPE_DWA2006414_HPP diff --git a/include/boost/parameter/aux_/preprocessor/flatten.hpp b/include/boost/parameter/aux_/preprocessor/flatten.hpp index cdd6f44..2bd7539 100755 --- a/include/boost/parameter/aux_/preprocessor/flatten.hpp +++ b/include/boost/parameter/aux_/preprocessor/flatten.hpp @@ -67,12 +67,12 @@ , spec \ ) -# define BOOST_PARAMETER_FLATTEN(optional_arity, required_arity, specs) \ +# define BOOST_PARAMETER_FLATTEN(optional_arity, required_arity, wanted_arity, specs) \ BOOST_PP_SEQ_FOR_EACH( \ BOOST_PARAMETER_FLATTEN_SPEC \ , ( \ optional_arity, required_arity \ - , BOOST_PP_MAX(optional_arity, required_arity) \ + , wanted_arity \ ) \ , specs \ ) diff --git a/include/boost/parameter/aux_/preprocessor/for_each.hpp b/include/boost/parameter/aux_/preprocessor/for_each.hpp index 22b2051..0eb1f70 100755 --- a/include/boost/parameter/aux_/preprocessor/for_each.hpp +++ b/include/boost/parameter/aux_/preprocessor/for_each.hpp @@ -14,6 +14,7 @@ # include # include # include +# include # define BOOST_PARAMETER_FOR_EACH_head_aux2(x,y) (x,y), ~ # define BOOST_PARAMETER_FOR_EACH_head_aux3(x,y,z) (x,y,z), ~ diff --git a/include/boost/parameter/parameters.hpp b/include/boost/parameter/parameters.hpp index 73ae328..5c5d013 100755 --- a/include/boost/parameter/parameters.hpp +++ b/include/boost/parameter/parameters.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -461,6 +462,13 @@ namespace aux } // namespace aux +#define BOOST_PARAMETER_FORWARD_TYPEDEF(z, i, names) \ + typedef BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0,names),i) BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names),i); + +#define BOOST_PARAMETER_FORWARD_TYPEDEFS(n, src, dest) \ + BOOST_PP_REPEAT(n, BOOST_PARAMETER_FORWARD_TYPEDEF, (src)(dest)) + + #define BOOST_PARAMETER_TEMPLATE_ARGS(z, n, text) class BOOST_PP_CAT(PS, n) = void_ template< @@ -564,27 +572,8 @@ struct parameters ), unnamed_list>::type type; }; - // Metafunction that returns an ArgumentPack. - template < -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) - // Borland simply can't handle default arguments in member - // class templates. People wishing to write portable code can - // explicitly specify BOOST_PARAMETER_MAX_ARITY arguments - BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, class A) -#else - BOOST_PP_ENUM_BINARY_PARAMS( - BOOST_PARAMETER_MAX_ARITY, class A, = void_ BOOST_PP_INTERCEPT - ) -#endif - > - struct argument_pack - { - typedef typename mpl::apply_wrap1::type type; - }; - + BOOST_PARAMETER_FORWARD_TYPEDEFS(BOOST_PARAMETER_MAX_ARITY, PS, parameter_spec) + // // The function call operator is used to build an arg_list that // labels the positional parameters and maintains whatever other @@ -654,10 +643,6 @@ struct parameters 3,BOOST_PARAMETER_MAX_ARITY, \ )) #include BOOST_PP_ITERATE() - -#undef BOOST_PARAMETER_build_arg_list -#undef BOOST_PARAMETER_make_arg_list -#undef BOOST_PARAMETER_right_angle }; diff --git a/include/boost/parameter/preprocessor.hpp b/include/boost/parameter/preprocessor.hpp index 04f03ba..bd6366d 100755 --- a/include/boost/parameter/preprocessor.hpp +++ b/include/boost/parameter/preprocessor.hpp @@ -9,6 +9,7 @@ # include # include +# include # include # include @@ -23,155 +24,45 @@ # include # include # include +# include + +# include # include # include namespace boost { namespace parameter { namespace aux { -# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) +# ifndef BOOST_NO_SFINAE -template -struct msvc_extract_type -{ - template - struct id2type_impl; - - typedef id2type_impl id2type; -}; - -template -struct msvc_register_type : msvc_extract_type -{ - template<> - struct id2type_impl //VC7.0 specific bugfeature - { - typedef T type; - }; -}; - -template -msvc_register_type unwrap_type_fn(void(*)(T)); - -template -struct unwrap_type -{ - BOOST_STATIC_CONSTANT(unsigned, - dummy = sizeof(unwrap_type_fn((T)0)) - ); - - typedef typename msvc_extract_type::id2type::type type; -}; - -# define BOOST_PARAMETER_FUNCTION_WRAP_TYPE(x) void(*) x - -# elif BOOST_WORKAROUND(BOOST_MSVC, < 1300) - -template -struct msvc_extract_type -{ - struct id2type; -}; - -template -struct msvc_register_type : msvc_extract_type -{ - typedef msvc_extract_type base_type; - struct base_type::id2type // This uses nice VC6.5 and VC7.1 bugfeature - { - typedef T type; - }; -}; - -template -msvc_register_type unwrap_type_fn(void(*)(T)); - -template -struct unwrap_type -{ - BOOST_STATIC_CONSTANT(unsigned, - dummy = sizeof(unwrap_type_fn((T)0)) - ); - - typedef typename msvc_extract_type::id2type::type type; -}; - -# define BOOST_PARAMETER_FUNCTION_WRAP_TYPE(x) void(*) x - -# elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) - -template +// Given Match, which is "void x" where x is an argument matching +// criterion, extract a corresponding MPL predicate. +template struct unwrap_predicate; -// Wildcard case +// Match anything template <> -struct unwrap_predicate +struct unwrap_predicate { typedef mpl::always type; }; -// Convertible to -template -struct unwrap_predicate +// A matching predicate is explicitly specified +template +struct unwrap_predicate { - typedef T type; + typedef Predicate type; }; -template -struct unwrap_predicate +// A type to which the argument is supposed to be convertible is +// specified +template +struct unwrap_predicate { - typedef is_convertible type; + typedef is_convertible type; }; -template -struct unwrap_type; - -template -struct unwrap_type -{ - typedef T type; -}; - -# define BOOST_PARAMETER_FUNCTION_WRAP_TYPE(x) void(*) x - -# else - -template -struct unwrap_predicate; - -// Wildcard case -template <> -struct unwrap_predicate -{ - typedef mpl::always type; -}; - -// Convertible to -template -struct unwrap_predicate -{ - typedef T type; -}; - -template -struct unwrap_predicate -{ - typedef is_convertible type; -}; - -template -struct unwrap_type; - -template -struct unwrap_type -{ - typedef T type; -}; - -# define BOOST_PARAMETER_FUNCTION_WRAP_TYPE(x) void x - -# endif - +// Recast the ParameterSpec's nested match metafunction as a free metafunction template < class Parameters , BOOST_PP_ENUM_BINARY_PARAMS( @@ -183,6 +74,7 @@ struct match BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, A) > {}; +# endif template < class Parameters @@ -192,13 +84,84 @@ template < > struct argument_pack { - typedef typename Parameters::template argument_pack< - BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, A) + typedef typename mpl::apply_wrap1< + BOOST_PARAMETER_build_arg_list( + BOOST_PARAMETER_MAX_ARITY, aux::make_partial_arg_list + , typename Parameters::parameter_spec, A, aux::tag_keyword_arg + ) + , typename Parameters::unnamed_list >::type type; }; +# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Works around VC6 problem where it won't accept rvalues. +template +T& as_lvalue(T& value, long) +{ + return value; +} + +template +T const& as_lvalue(T const& value, int) +{ + return value; +} +# endif + }}} // namespace boost::parameter::aux +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +// From Paul Mensonides +# define BOOST_PARAMETER_IS_NULLARY(x) \ + BOOST_PP_SPLIT(1, BOOST_PARAMETER_IS_NULLARY_C x BOOST_PP_COMMA() 0) \ + /**/ +# define BOOST_PARAMETER_IS_NULLARY_C() \ + ~, 1 BOOST_PP_RPAREN() \ + BOOST_PP_TUPLE_EAT(2) BOOST_PP_LPAREN() ~ \ + /**/ +# else +# define BOOST_PARAMETER_IS_NULLARY(x) BOOST_PP_IS_NULLARY(x) +# endif + +# define BOOST_PARAMETER_MEMBER_FUNCTION_CHECK_STATIC_static () +# define BOOST_PARAMETER_MEMBER_FUNCTION_IS_STATIC(name) \ + BOOST_PARAMETER_IS_NULLARY( \ + BOOST_PP_CAT(BOOST_PARAMETER_MEMBER_FUNCTION_CHECK_STATIC_,name) \ + ) + +# if !defined(BOOST_MSVC) +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_static +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC(name) \ + BOOST_PP_CAT(BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_, name) +# else +// Workaround for MSVC preprocessor. +// +// When stripping static from "static f", msvc will produce +// " f". The leading whitespace doesn't go away when pasting +// the token with something else, so this thing is a hack to +// strip the whitespace. +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_static ( +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_AUX(name) \ + BOOST_PP_CAT(BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_, name)) +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC(name) \ + BOOST_PP_SEQ_HEAD( \ + BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_AUX(name) \ + ) +# endif + +# define BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(name) \ + BOOST_PP_EXPR_IF( \ + BOOST_PARAMETER_MEMBER_FUNCTION_IS_STATIC(name) \ + , static \ + ) + +# define BOOST_PARAMETER_MEMBER_FUNCTION_NAME(name) \ + BOOST_PP_IF( \ + BOOST_PARAMETER_MEMBER_FUNCTION_IS_STATIC(name) \ + , BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC \ + , name BOOST_PP_TUPLE_EAT(1) \ + )(name) + // Calculates [begin, end) arity range. # define BOOST_PARAMETER_ARITY_RANGE_M_optional(state) state @@ -218,20 +181,27 @@ struct argument_pack ) /**/ +// Accessor macros for the argument specs tuple. # define BOOST_PARAMETER_FN_ARG_QUALIFIER(x) \ - BOOST_PP_TUPLE_ELEM(3,0,x) + BOOST_PP_TUPLE_ELEM(4,0,x) /**/ # define BOOST_PARAMETER_FN_ARG_NAME(x) \ - BOOST_PP_TUPLE_ELEM(3,1,x) + BOOST_PP_TUPLE_ELEM(4,1,x) /**/ # define BOOST_PARAMETER_FN_ARG_PRED(x) \ - BOOST_PP_TUPLE_ELEM(3,2,x) + BOOST_PP_TUPLE_ELEM(4,2,x) +/**/ + +# define BOOST_PARAMETER_FN_ARG_DEFAULT(x) \ + BOOST_PP_TUPLE_ELEM(4,3,x) /**/ # define BOOST_PARAMETETER_FUNCTION_EAT_KEYWORD_QUALIFIER_out(x) # define BOOST_PARAMETETER_FUNCTION_EAT_KEYWORD_QUALIFIER_in_out(x) + +// Returns 1 if x is either "out(k)" or "in_out(k)". # define BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER(x) \ BOOST_PP_IS_EMPTY( \ BOOST_PP_CAT(BOOST_PARAMETETER_FUNCTION_EAT_KEYWORD_QUALIFIER_, x) \ @@ -244,6 +214,13 @@ struct argument_pack BOOST_PP_CAT(BOOST_PARAMETETER_FUNCTION_GET_KEYWORD_QUALIFIER_, x) /**/ +// Returns the keyword of x, where x is either a keyword qualifier +// or a keyword. +// +// k => k +// out(k) => k +// in_out(k) => k +// # define BOOST_PARAMETER_FUNCTION_KEYWORD(x) \ BOOST_PP_IF( \ BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER(x) \ @@ -252,6 +229,11 @@ struct argument_pack )(x) /**/ +# define BOOST_PARAMETER_FN_ARG_KEYWORD(x) \ + BOOST_PARAMETER_FUNCTION_KEYWORD( \ + BOOST_PARAMETER_FN_ARG_NAME(x) \ + ) + // Builds forwarding functions. # define BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_TEMPLATE_Z(z, n) \ @@ -269,20 +251,35 @@ struct argument_pack /**/ # define BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(base) \ - BOOST_PP_CAT(BOOST_PP_CAT(base, _parameters), __LINE__) + BOOST_PP_CAT( \ + boost_param_parameters_ \ + , BOOST_PP_CAT(__LINE__, BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base)) \ + ) +// Produce a name for a result type metafunction for the function +// named base # define BOOST_PARAMETER_FUNCTION_RESULT_NAME(base) \ - BOOST_PP_CAT(BOOST_PP_CAT(base, _result), __LINE__) + BOOST_PP_CAT( \ + boost_param_result_ \ + , BOOST_PP_CAT(__LINE__,BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base)) \ + ) + +// Can't do boost_param_impl_ ## basee because base might start with an underscore +// daniel: what? how is that relevant? the reason for using CAT() is to make sure +// base is expanded. i'm not sure we need to here, but it's more stable to do it. +# define BOOST_PARAMETER_IMPL(base) \ + BOOST_PP_CAT(boost_param_impl,BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base)) # define BOOST_PARAMETER_FUNCTION_FWD_FUNCTION00(z, n, r, data, elem) \ BOOST_PP_IF( \ n \ , BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_TEMPLATE_Z, BOOST_PP_TUPLE_EAT(2) \ )(z,n) \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(BOOST_PP_TUPLE_ELEM(7,3,data)) \ inline \ - BOOST_PP_EXPR_IF(n, typename) boost::mpl::apply_wrap1< \ - BOOST_PARAMETER_FUNCTION_RESULT_NAME(BOOST_PP_TUPLE_ELEM(7,3,data)) \ - , BOOST_PP_EXPR_IF(n, typename) \ + BOOST_PP_EXPR_IF(n, typename) \ + BOOST_PARAMETER_FUNCTION_RESULT_NAME(BOOST_PP_TUPLE_ELEM(7,3,data))< \ + BOOST_PP_EXPR_IF(n, typename) \ boost::parameter::aux::argument_pack< \ BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(BOOST_PP_TUPLE_ELEM(7,3,data)) \ BOOST_PP_COMMA_IF(n) \ @@ -291,7 +288,7 @@ struct argument_pack )(elem) \ >::type \ >::type \ - BOOST_PP_TUPLE_ELEM(7,3,data)( \ + BOOST_PARAMETER_MEMBER_FUNCTION_NAME(BOOST_PP_TUPLE_ELEM(7,3,data))( \ BOOST_PP_IF( \ n \ , BOOST_PP_SEQ_FOR_EACH_I_R \ @@ -310,7 +307,7 @@ struct argument_pack ) \ ) BOOST_PP_EXPR_IF(BOOST_PP_TUPLE_ELEM(7,4,data), const) \ { \ - return BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(7,3,data), _impl)( \ + return BOOST_PARAMETER_IMPL(BOOST_PP_TUPLE_ELEM(7,3,data))( \ BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(BOOST_PP_TUPLE_ELEM(7,3,data))()( \ BOOST_PP_ENUM_PARAMS_Z(z, n, a) \ ) \ @@ -374,28 +371,15 @@ struct argument_pack /**/ // Builds boost::parameter::parameters<> specialization -# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) # define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ BOOST_PP_COMMA_IF(i) \ boost::parameter::BOOST_PARAMETER_FN_ARG_QUALIFIER(elem)< \ tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ - BOOST_PARAMETER_FN_ARG_NAME(elem) \ - ) \ - , typename boost::parameter::aux::unwrap_predicate< \ - void (*)BOOST_PARAMETER_FN_ARG_PRED(elem) \ - , BoostParameterDummyTemplateArg \ - >::type \ - > -# elif !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) -# define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ - BOOST_PP_COMMA_IF(i) \ - boost::parameter::BOOST_PARAMETER_FN_ARG_QUALIFIER(elem)< \ - tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ - BOOST_PARAMETER_FN_ARG_NAME(elem) \ + BOOST_PARAMETER_FN_ARG_KEYWORD(elem) \ ) \ , typename boost::parameter::aux::unwrap_predicate< \ void BOOST_PARAMETER_FN_ARG_PRED(elem) \ - , BoostParameterDummyTemplateArg \ >::type \ > # else @@ -403,124 +387,391 @@ struct argument_pack BOOST_PP_COMMA_IF(i) \ boost::parameter::BOOST_PARAMETER_FN_ARG_QUALIFIER(elem)< \ tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ - BOOST_PARAMETER_FN_ARG_NAME(elem) \ + BOOST_PARAMETER_FN_ARG_KEYWORD(elem) \ ) \ , boost::mpl::always \ > # endif /**/ -# define BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, args) \ - template \ - struct BOOST_PP_CAT(boost_parameter_parameters_type, __LINE__) \ - : boost::parameter::parameters< \ - BOOST_PP_SEQ_FOR_EACH_I( \ - BOOST_PARAMETER_FUNCTION_PARAMETERS_M, tag_namespace, args \ - ) \ - > \ - {}; \ -\ - typedef BOOST_PP_CAT(boost_parameter_parameters_type, __LINE__)<> -/**/ +# define BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, base, args) \ + template \ + struct BOOST_PP_CAT( \ + BOOST_PP_CAT(boost_param_params_, __LINE__) \ + , BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base) \ + ) : boost::parameter::parameters< \ + BOOST_PP_SEQ_FOR_EACH_I( \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_M, tag_namespace, args \ + ) \ + > \ + {}; \ + \ + typedef BOOST_PP_CAT( \ + BOOST_PP_CAT(boost_param_params_, __LINE__) \ + , BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base) \ + ) // Defines result type metafunction # define BOOST_PARAMETER_FUNCTION_RESULT_ARG(z, _, i, x) \ BOOST_PP_COMMA_IF(i) class BOOST_PP_TUPLE_ELEM(3,1,x) /**/ -# define BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ - struct BOOST_PARAMETER_FUNCTION_RESULT_NAME(name) \ - { \ - template \ - struct apply \ - { \ - template \ - struct binding \ - : boost::parameter::binding \ - {}; \ -\ - typedef boost::parameter::aux::unwrap_type< \ - BOOST_PARAMETER_FUNCTION_WRAP_TYPE(result) \ - >::type type; \ - }; \ +# define BOOST_PARAMETER_FUNCTION_RESULT_(result, name, args) \ + template \ + struct BOOST_PARAMETER_FUNCTION_RESULT_NAME(name) \ + { \ + typedef typename BOOST_PARAMETER_PARENTHESIZED_TYPE(result) type; \ }; -/**/ + +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + +# define BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ + BOOST_PARAMETER_FUNCTION_RESULT_(result, name, args) \ + template <> \ + struct BOOST_PARAMETER_FUNCTION_RESULT_NAME(name) \ + { typedef int type; }; + +# else + +# define BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ + BOOST_PARAMETER_FUNCTION_RESULT_(result, name, args) + +# endif // Defines implementation function -# define BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) \ - template \ - typename boost::mpl::apply_wrap1< \ - BOOST_PARAMETER_FUNCTION_RESULT_NAME(name), Args \ - >::type BOOST_PP_CAT(name, _impl)(Args const& args) -/**/ +# define BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) \ + template \ + typename BOOST_PARAMETER_FUNCTION_RESULT_NAME(name)< \ + Args \ + >::type BOOST_PARAMETER_IMPL(name)(Args const& args) # define BOOST_PARAMETER_FUNCTION_IMPL_FWD(name) \ BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name); /**/ -// Defines a Boost.Parameter enabled function. -# define BOOST_PARAMETER_FUNCTION_AUX(result, name, tag_namespace, args) \ - namespace \ - { \ - BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ -\ - BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, args) \ - BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(name); \ - } \ -\ - BOOST_PARAMETER_FUNCTION_IMPL_FWD(name) \ -\ - BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ - result, name, args, 0 \ - , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ - ) \ -\ - BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_required(state, arg) \ + ( \ + BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4, 0, state)) \ + , BOOST_PP_SEQ_PUSH_BACK(BOOST_PP_TUPLE_ELEM(4, 1, state), arg) \ + , BOOST_PP_TUPLE_ELEM(4, 2, state) \ + , BOOST_PP_TUPLE_ELEM(4, 3, state) \ + ) -# define BOOST_PARAMETER_FUNCTION(result, name, tag_namespace, args) \ - BOOST_PARAMETER_FUNCTION_AUX( \ - result, name, tag_namespace \ - , BOOST_PARAMETER_FLATTEN(2, 2, args) \ +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_optional(state, arg) \ + ( \ + BOOST_PP_TUPLE_ELEM(4, 0, state) \ + , BOOST_PP_TUPLE_ELEM(4, 1, state) \ + , BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4, 2, state)) \ + , BOOST_PP_SEQ_PUSH_BACK(BOOST_PP_TUPLE_ELEM(4, 3, state), arg) \ + ) + +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG(s, state, arg) \ + BOOST_PP_CAT( \ + BOOST_PARAMETER_FUNCTION_SPLIT_ARG_ \ + , BOOST_PARAMETER_FN_ARG_QUALIFIER(arg) \ + )(state, arg) + +// Returns (required_count, required, optional_count, optionals) tuple +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARGS(args) \ + BOOST_PP_SEQ_FOLD_LEFT( \ + BOOST_PARAMETER_FUNCTION_SPLIT_ARG \ + , (0,BOOST_PP_SEQ_NIL, 0,BOOST_PP_SEQ_NIL) \ + , args \ + ) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG_NAME(keyword) \ + BOOST_PP_CAT(BOOST_PP_CAT(keyword,_),type) + +// Helpers used as parameters to BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_TEMPLATE_ARG(r, _, arg) \ + , class BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG_NAME( \ + BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ + ) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG(r, _, arg) \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG_NAME( \ + BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ + )& BOOST_PARAMETER_FN_ARG_KEYWORD(arg) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_PARAMETER(r, _, arg) \ + , BOOST_PARAMETER_FN_ARG_KEYWORD(arg) + +// Produces a name for the dispatch functions. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name) \ + BOOST_PP_CAT( \ + boost_param_default_ \ + , BOOST_PP_CAT(__LINE__, BOOST_PARAMETER_MEMBER_FUNCTION_NAME(name)) \ + ) + +// Helper macro used below to produce lists based on the keyword argument +// names. macro is applied to every element. n is the number of +// optional arguments that should be included. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS(macro, n, split_args) \ + BOOST_PP_SEQ_FOR_EACH( \ + macro \ + , ~ \ + , BOOST_PP_TUPLE_ELEM(4,1,split_args) \ + ) \ + BOOST_PP_SEQ_FOR_EACH( \ + macro \ + , ~ \ + , BOOST_PP_SEQ_FIRST_N( \ + BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(4,2,split_args), n) \ + , BOOST_PP_TUPLE_ELEM(4,3,split_args) \ + ) \ + ) + +// Generates a keyword | default expression. +# if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT(arg) \ + BOOST_PARAMETER_FN_ARG_KEYWORD(arg) | BOOST_PARAMETER_FN_ARG_DEFAULT(arg) +# else // For some reason, VC6 won't accept rvalues in this context. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT(arg) \ + BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ + | boost::parameter::aux::as_lvalue(BOOST_PARAMETER_FN_ARG_DEFAULT(arg), 0L) +# endif + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_BODY(name, n, split_args) \ + { \ + return BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ + (ResultType(*)())0 \ + , args \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_PARAMETER \ + , n \ + , split_args \ + ) \ + , args[ \ + BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT( \ + BOOST_PP_SEQ_ELEM( \ + BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(4,2,split_args), n) \ + , BOOST_PP_TUPLE_ELEM(4,3,split_args) \ + ) \ + ) \ + ] \ + ); \ + } + +// Produces a forwarding layer in the default evaluation machine. +// +// data is a tuple: +// +// (name, split_args) +// +// Where name is the base name of the function, and split_args is a tuple: +// +// (required_count, required_args, optional_count, required_args) +// +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION(z, n, data) \ + template < \ + class ResultType \ + , class Args \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_TEMPLATE_ARG \ + , n \ + , BOOST_PP_TUPLE_ELEM(3,1,data) \ + ) \ + > \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(BOOST_PP_TUPLE_ELEM(3,0,data)) \ + ResultType BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(BOOST_PP_TUPLE_ELEM(3,0,data))( \ + ResultType(*)() \ + , Args const& args \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG \ + , n \ + , BOOST_PP_TUPLE_ELEM(3,1,data) \ + ) \ + ) BOOST_PP_EXPR_IF(BOOST_PP_TUPLE_ELEM(3,2,data), const) \ + BOOST_PP_IF( \ + n \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_BODY \ + , ; BOOST_PP_TUPLE_EAT(3) \ + )(BOOST_PP_TUPLE_ELEM(3,0,data), n, BOOST_PP_TUPLE_ELEM(3,1,data)) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_GET_ARG(r, _, arg) \ + , args[BOOST_PARAMETER_FN_ARG_KEYWORD(arg)] + +// Generates the function template that recives a ArgumentPack, and then +// goes on to call the layers of overloads generated by +// BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER. +# define BOOST_PARAMETER_FUNCTION_INITIAL_DISPATCH_FUNCTION(name, split_args, const_) \ + template \ + typename BOOST_PARAMETER_FUNCTION_RESULT_NAME(name)::type \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(name) \ + BOOST_PARAMETER_IMPL(name)(Args const& args) BOOST_PP_EXPR_IF(const_, const) \ + { \ + return BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ + (typename BOOST_PARAMETER_FUNCTION_RESULT_NAME(name)::type(*)())0 \ + , args \ + \ + BOOST_PP_SEQ_FOR_EACH( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_GET_ARG \ + , ~ \ + , BOOST_PP_TUPLE_ELEM(4,1,split_args) \ + ) \ + \ + ); \ + } + +// Helper for BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER below. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER_AUX(name, split_args, skip_fwd_decl, const_) \ + BOOST_PP_REPEAT_FROM_TO( \ + skip_fwd_decl \ + , BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4, 2, split_args)) \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION \ + , (name, split_args, const_) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_INITIAL_DISPATCH_FUNCTION(name, split_args, const_) \ +\ + template < \ + class ResultType \ + , class Args \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_TEMPLATE_ARG \ + , 0 \ + , split_args \ + ) \ + > \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(name) \ + ResultType BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ + ResultType(*)() \ + , Args const& args \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG \ + , 0 \ + , split_args \ + ) \ + ) BOOST_PP_EXPR_IF(const_, const) + +// Generates a bunch of forwarding functions that each extract +// one more argument. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, skip_fwd_decl, const_) \ + BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER_AUX( \ + name, BOOST_PARAMETER_FUNCTION_SPLIT_ARGS(args), skip_fwd_decl, const_ \ ) /**/ -// Defines a Boost.Parameter enabled member function. -# define BOOST_PARAMETER_MEMBER_FUNCTION_AUX(result, name, tag_namespace, args, const_) \ - BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ +// Defines the result metafunction and the parameters specialization. +# define BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ + \ + BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, name, args) \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(name); \ + +// Helper for BOOST_PARAMETER_FUNCTION below. +# define BOOST_PARAMETER_FUNCTION_AUX(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name); \ \ - BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, args) \ - BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(name); \ -\ - BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ - result, name, args, const_ \ - , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ - ) \ -\ - BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) BOOST_PP_EXPR_IF(const_, const) + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ + result, name, args, 0 \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, 0, 0) + +// Defines a Boost.Parameter enabled function with the new syntax. +# define BOOST_PARAMETER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_AUX( \ + result, name, tag_namespace \ + , BOOST_PARAMETER_FLATTEN(3, 2, 3, args) \ + ) \ /**/ -# define BOOST_PARAMETER_MEMBER_FUNCTION(result, name, tag_namespace, args) \ - BOOST_PARAMETER_MEMBER_FUNCTION_AUX( \ +// Defines a Boost.Parameter enabled function. +# define BOOST_PARAMETER_BASIC_FUNCTION_AUX(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ + \ + BOOST_PARAMETER_FUNCTION_IMPL_FWD(name) \ + \ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ + result, name, args, 0 \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) + +# define BOOST_PARAMETER_BASIC_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_BASIC_FUNCTION_AUX( \ + result, name, tag_namespace \ + , BOOST_PARAMETER_FLATTEN(2, 2, 3, args) \ + ) \ +/**/ + +// Defines a Boost.Parameter enabled member function. +# define BOOST_PARAMETER_BASIC_MEMBER_FUNCTION_AUX(result, name, tag_namespace, args, const_) \ + BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ + \ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ + result, name, args, const_ \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) BOOST_PP_EXPR_IF(const_, const) \ +/**/ + +# define BOOST_PARAMETER_BASIC_MEMBER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION_AUX( \ result, name, tag_namespace \ - , BOOST_PARAMETER_FLATTEN(2, 2, args) \ + , BOOST_PARAMETER_FLATTEN(2, 2, 3, args) \ , 0 \ ) /**/ -# define BOOST_PARAMETER_CONST_MEMBER_FUNCTION(result, name, tag_namespace, args) \ - BOOST_PARAMETER_MEMBER_FUNCTION_AUX( \ +# define BOOST_PARAMETER_BASIC_CONST_MEMBER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION_AUX( \ result, name, tag_namespace \ - , BOOST_PARAMETER_FLATTEN(2, 2, args) \ + , BOOST_PARAMETER_FLATTEN(2, 2, 3, args) \ , 1 \ ) /**/ + + +# define BOOST_PARAMETER_MEMBER_FUNCTION_AUX(result, name, tag_namespace, const_, args) \ + BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ +\ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ + result, name, args, const_ \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, 1, const_) + +// Defines a Boost.Parameter enabled function with the new syntax. +# define BOOST_PARAMETER_MEMBER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_MEMBER_FUNCTION_AUX( \ + result, name, tag_namespace, 0 \ + , BOOST_PARAMETER_FLATTEN(3, 2, 3, args) \ + ) \ +/**/ + +# define BOOST_PARAMETER_CONST_MEMBER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_MEMBER_FUNCTION_AUX( \ + result, name, tag_namespace, 1 \ + , BOOST_PARAMETER_FLATTEN(3, 2, 3, args) \ + ) \ +/**/ + // Defines a Boost.Parameter enabled constructor. # define BOOST_PARAMETER_FUNCTION_ARGUMENT(r, _, i, elem) \ BOOST_PP_COMMA_IF(i) elem& BOOST_PP_CAT(a, i) /**/ +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + +// Older MSVC can't do what's necessary to handle commas in base names; just +// use a typedef instead if you have a base name that contains commas. +# define BOOST_PARAMETER_PARENTHESIZED_BASE(x) BOOST_PP_SEQ_HEAD(x) + +# else + +# define BOOST_PARAMETER_PARENTHESIZED_BASE(x) BOOST_PARAMETER_PARENTHESIZED_TYPE(x) + +# endif + # define BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR00(z, n, r, data, elem) \ BOOST_PP_IF( \ n \ @@ -545,9 +796,7 @@ struct argument_pack , n \ ) \ ) \ - : boost::parameter::aux::unwrap_type< \ - BOOST_PARAMETER_FUNCTION_WRAP_TYPE(BOOST_PP_TUPLE_ELEM(6,3,data)) \ - >::type( \ + : BOOST_PARAMETER_PARENTHESIZED_BASE(BOOST_PP_TUPLE_ELEM(6,3,data)) ( \ BOOST_PP_CAT(constructor_parameters, __LINE__)()( \ BOOST_PP_ENUM_PARAMS_Z(z, n, a) \ ) \ @@ -613,7 +862,7 @@ struct argument_pack /**/ # define BOOST_PARAMETER_CONSTRUCTOR_AUX(class_, base, tag_namespace, args) \ - BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, ctor, args) \ BOOST_PP_CAT(constructor_parameters, __LINE__); \ \ BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTORS( \ @@ -625,22 +874,28 @@ struct argument_pack # define BOOST_PARAMETER_CONSTRUCTOR(class_, base, tag_namespace, args) \ BOOST_PARAMETER_CONSTRUCTOR_AUX( \ class_, base, tag_namespace \ - , BOOST_PARAMETER_FLATTEN(2, 2, args) \ + , BOOST_PARAMETER_FLATTEN(2, 2, 3, args) \ ) /**/ -# if 1 //ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +# if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) # define BOOST_PARAMETER_FUNCTION_FWD_COMBINATION(r, _, i, elem) \ (BOOST_PP_IF( \ BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER( \ - BOOST_PP_TUPLE_ELEM(3,1,elem) \ + BOOST_PARAMETER_FN_ARG_NAME(elem) \ ) \ , (const ParameterArgumentType ## i)(ParameterArgumentType ## i) \ , (const ParameterArgumentType ## i) \ )) # else # define BOOST_PARAMETER_FUNCTION_FWD_COMBINATION(r, _, i, elem) \ - ((ParameterArgumentType ## i)) + (BOOST_PP_IF( \ + BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER( \ + BOOST_PARAMETER_FN_ARG_NAME(elem) \ + ) \ + , (ParameterArgumentType ## i) \ + , (const ParameterArgumentType ## i) \ + )) # endif # define BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ diff --git a/include/boost/parameter/python.hpp b/include/boost/parameter/python.hpp index 5a24d66..252ec03 100755 --- a/include/boost/parameter/python.hpp +++ b/include/boost/parameter/python.hpp @@ -22,6 +22,7 @@ # include # include # include +# include # include # include # include @@ -323,7 +324,29 @@ namespace aux Def, Specs*, End, End, Invoker*) {} - template + struct not_specified {}; + + template + struct call_policies_as_options + { + call_policies_as_options(CallPolicies const& call_policies) + : call_policies(call_policies) + {} + + CallPolicies const& policies() const + { + return call_policies; + } + + char const* doc() const + { + return 0; + } + + CallPolicies call_policies; + }; + + template struct def_class { def_class(Class& cl, char const* name, Options options = Options()) @@ -333,7 +356,7 @@ namespace aux {} template - void def(F f, int const*) const + void def(F f, not_specified const*) const { cl.def(name, f); } @@ -351,7 +374,7 @@ namespace aux } template - void def(F f, Keywords const& keywords, int const*) const + void def(F f, Keywords const& keywords, not_specified const*) const { cl.def(name, f, keywords); } @@ -373,11 +396,12 @@ namespace aux Options options; }; - template + template struct def_init { - def_init(Class& cl) + def_init(Class& cl, CallPolicies call_policies = CallPolicies()) : cl(cl) + , call_policies(call_policies) {} template @@ -385,7 +409,7 @@ namespace aux { cl.def( "__init__" - , boost::python::make_constructor(f) + , boost::python::make_constructor(f, call_policies) ); } @@ -394,13 +418,12 @@ namespace aux { cl.def( "__init__" - , boost::python::make_constructor( - f, boost::python::default_call_policies(), keywords - ) + , boost::python::make_constructor(f, call_policies, keywords) ); } Class& cl; + CallPolicies call_policies; }; struct def_function @@ -440,6 +463,7 @@ void def(char const* name, Signature) typename M::keywords , arg_types , aux::make_arg_spec + , mpl::back_inserter > >::type arg_specs; typedef typename mpl::count_if< @@ -473,6 +497,7 @@ void def(Class& cl, char const* name, Signature) typename M::keywords , arg_types , aux::make_arg_spec + , mpl::back_inserter > >::type arg_specs; typedef typename mpl::count_if< @@ -503,8 +528,15 @@ namespace aux template struct keyword - : keyword - {}; + { + typedef K type; + }; + + template + struct keyword + { + typedef K type; + }; template struct required @@ -529,114 +561,159 @@ namespace aux { typedef mpl::false_ type; }; - + + template + struct make_kw_spec; + template - struct make_kw_spec + struct make_kw_spec { typedef arg_spec< typename keyword::type , typename required::type , typename optimized::type , T - > type; + > type; }; } // namespace aux -template +template struct init - : boost::python::def_visitor > + : boost::python::def_visitor > { + init(CallPolicies call_policies = CallPolicies()) + : call_policies(call_policies) + {} + + template + init + operator[](CallPolicies1 const& call_policies) const + { + return init(call_policies); + } + template - void visit(Class& cl) const + void visit_aux(Class& cl, mpl::true_) const + { + cl.def(boost::python::init<>()[call_policies]); + } + + template + void visit_aux(Class& cl, mpl::false_) const { typedef typename mpl::transform< - Keywords - , Signature - , aux::make_kw_spec + ParameterSpecs + , aux::make_kw_spec + , mpl::back_inserter > >::type arg_specs; typedef typename mpl::count_if< arg_specs - , aux::is_optional + , aux::is_optional >::type optional_arity; typedef typename mpl::shift_left, optional_arity>::type upper; aux::def_combinations( - aux::def_init(cl) + aux::def_init(cl, call_policies) , (arg_specs*)0 , mpl::long_<0>() , mpl::long_() , (aux::make_init_invoker*)0 ); } + + template + void visit(Class& cl) const + { + visit_aux(cl, mpl::empty()); + } + + CallPolicies call_policies; }; -template +template struct call - : boost::python::def_visitor > + : boost::python::def_visitor > { + call(CallPolicies const& call_policies = CallPolicies()) + : call_policies(call_policies) + {} + + template + call + operator[](CallPolicies1 const& call_policies) const + { + return call(call_policies); + } + template void visit(Class& cl) const { typedef mpl::iterator_range< typename mpl::next< - typename mpl::begin::type + typename mpl::begin::type >::type - , typename mpl::end::type + , typename mpl::end::type > arg_types; + typedef typename mpl::front::type result_type; + typedef typename mpl::transform< - Keywords - , arg_types - , aux::make_kw_spec + arg_types + , aux::make_kw_spec + , mpl::back_inserter > >::type arg_specs; typedef typename mpl::count_if< arg_specs - , aux::is_optional + , aux::is_optional >::type optional_arity; - typedef typename mpl::front::type result_type; typedef typename mpl::shift_left, optional_arity>::type upper; + typedef aux::call_policies_as_options options; + aux::def_combinations( - aux::def_class(cl, "__call__") + aux::def_class(cl, "__call__", options(call_policies)) , (arg_specs*)0 , mpl::long_<0>() , mpl::long_() , (aux::make_call_invoker*)0 ); } + + CallPolicies call_policies; }; -template +template struct function - : boost::python::def_visitor > + : boost::python::def_visitor > { template void visit(Class& cl, char const* name, Options const& options) const { typedef mpl::iterator_range< typename mpl::next< - typename mpl::begin::type + typename mpl::begin::type >::type - , typename mpl::end::type + , typename mpl::end::type > arg_types; + typedef typename mpl::front::type result_type; + typedef typename mpl::transform< - Keywords - , arg_types - , aux::make_kw_spec + arg_types + , aux::make_kw_spec + , mpl::back_inserter > >::type arg_specs; typedef typename mpl::count_if< arg_specs - , aux::is_optional + , aux::is_optional >::type optional_arity; - typedef typename mpl::front::type result_type; typedef typename mpl::shift_left, optional_arity>::type upper; aux::def_combinations( From 7eb7737095fa626780d9002be5101497c4f0b70c Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 22 Aug 2006 14:01:34 +0000 Subject: [PATCH 11/58] merged from trunk [SVN r34918] --- doc/html/index.html | 2204 +++++++++++++++++++++++++---------------- doc/index.rst | 2268 ++++++++++++++++++++++++++----------------- 2 files changed, 2746 insertions(+), 1726 deletions(-) diff --git a/doc/html/index.html b/doc/html/index.html index 39c8670..64fd52d 100755 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -3,27 +3,35 @@ - + The Boost Parameter Library

The Boost Parameter Library

+

Boost


- @@ -49,71 +57,97 @@ or copy at http
Abstract:

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

+
Abstract:

Use this library to write functions and class templates +that can accept arguments by name:

-new_window("alert", width=10, titlebar=false);
+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 has more than one parameter -with a useful default value.

+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.


-
-

Table of Contents

+
+

Table of Contents


-
-

1   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:

+
+

1   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:

    -
  • Since an argument's meaning is given by its position, we have to +

  • +

    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:

    -
    +
     window* new_window(
    -   char const* name, 
    +   char const* name,
        int border_width = default_border_width,
        bool movable = true,
        bool initially_visible = true
    @@ -122,80 +156,109 @@ window* new_window(
     const bool movability = false;
     window* w = new_window("alert box", movability);
     
    -

    In the example above we wanted to make an unmoveable window +

    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:

    -
    +
     window* w = new_window(
        "alert box", default_border_width, movability);
     
    +
  • -
  • It can become difficult for readers to understand the meaning of +

  • +

    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 +

    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:

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

1.1   Named Function Parameters

+
+

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:

+
+window* w = new_window("alert box", movable_=false); // OK!
 
-
- +
+

1.2   Deduced Function Parameters

+
+

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:

+
+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.

+
+
+
+

1.3   Class Template Parameter Support

+
+

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:

+
+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:

+
+// p and q could be equivalent, given a deduced
+// parameter interface.
+smart_ptr<shared, Client> p;
+smart_ptr<Client, shared> q;
+
+
+
+
+
+

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.

+
+

2.1   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 -depth_first_search algorithm.1 After laying some groundwork +depth_first_search algorithm.1

+ +
+

2.1.1   Headers And Namespaces

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

@@ -215,8 +278,8 @@ namespace parameter = boost::parameter;
 

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

-
-

2.2   The Abstract Interface to depth_first_search

+
+

2.1.2   The Abstract Interface to depth_first_search

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

@@ -225,7 +288,7 @@ template < class Graph, class DFSVisitor, class Index, class ColorMap > void depth_first_search( - , Graph const& graph + , Graph const& graph , DFSVisitor visitor , typename graph_traits<g>::vertex_descriptor root_vertex , IndexMap index_map @@ -233,38 +296,53 @@ void depth_first_search(

However, most of the parameters have a useful default value, as shown in the table below.

- - +
depth_first_search Parameters
+--+++ - - - + + + + + + + + - + +
depth_first_search Parameters
Parameter NameDataflowDefault Value (if any)
Parameter NameDataflowTypeDefault Value (if any)
graph inModel of Incidence Graph and +Vertex List Graph none - this argument is required.
visitor inModel of DFS Visitor boost::dfs_visitor<>()
root_vertex ingraph's vertex descriptor +type. *vertices(graph).first
index_map inModel of Readable Property Map +with key type := graph's +vertex descriptor and value type +an integer type. get(boost::vertex_index,graph)
color_mapoutin/outModel of Read/Write Property +Map with key type := +graph's vertex descriptor +type. an iterator_property_map created from a std::vector of default_color_type of size @@ -273,656 +351,958 @@ created from a std::vector
-

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.

+

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.

-
-

2.3   Defining the Keywords

+
+

2.1.3   Defining the Keywords

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

-graphs::depth_first_search(g, color_map = my_color_map);
+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 +“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.

-

We're going to define our interface in namespace graphs. Since + +

We're going to define our interface in namespace graphs. The +library provides a convenient macro for defining keyword objects:

-#include <boost/parameter/keyword.hpp>
+#include <boost/parameter/name.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)
+  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)
 }
 
-

The declaration of the visitor keyword you see here is +

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

-namespace graphs 
+namespace graphs
 {
-  namespace tag { struct visitor; }
-  namespace { 
-    boost::parameter::keyword<tag::visitor>& visitor
-    = boost::parameter::keyword<tag::visitor>::get();
+  namespace tag { struct graph; } // keyword tag type
+
+  namespace // unnamed
+  {
+    // A reference to the keyword object
+    boost::parameter::keyword<tag::graph>& _graph
+    = boost::parameter::keyword<tag::graph>::instance;
   }
 }
 
-

This “fancy dance” involving the unnamed namespace and references -is all done to avoid violating the One Definition Rule (ODR)2 when the named parameter interface is used by function +

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)2 when the named parameter interface is used by function templates that are instantiated in multiple translation -units.

+units (MSVC6.x users see this note).

-
-

2.4   Defining the Implementation Function

-

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

+
+

2.1.4   Writing the Function

+

Now that we have our keywords defined, the function template +definition follows a simple pattern using the +BOOST_PARAMETER_FUNCTION macro:

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

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:

-
-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:

-
-int main()
-{
-    using namespace graphs;
+#include <boost/parameter/function.hpp>
 
-    core::depth_first_search((
-      graph = 'G', visitor = 2, root_vertex = 3.5, 
-      index_map = "hello, world", color_map = false));
+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))
+        (in_out(color_map), *,
+          default_color_map(num_vertices(graph), index_map) )
+      )
+  )
+  {
+      // ... body of function goes here...
+      // use graph, visitor, index_map, and color_map
+  }
 }
 
-

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
-
-
-
-

2.5   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.

-
-

2.5.1   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".

-
-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 -or, if no argument is passed explicitly, to the specified -default value.

-
-
-
-

2.5.2   Getting More Realistic

-

Now it's time to put some more realistic defaults in place. We'll -have to give up our print statements—at least if we want to see the -defaults work—since, the default values of these -parameters generally aren't printable.

-

Instead, we'll connect local variables to the arguments and use -those in our algorithm:

-
-namespace graphs { namespace core
-{
-  template <class ArgumentPack>
-  void depth_first_search(ArgumentPack const& args)
-  {
-      Graph   g = args[graph];
-      Visitor v = args[visitor|default-expression1];
-      Vertex  s = args[root_vertex|default-expression2];
-      Index   i = args[index_map|default-expression3];
-      Color   c = args[visitor|default-expression4];
-
-      …use g, v, s, i, and c to implement the algorithm…
-  }
-}} // graphs::core
-
-

We'll insert the default expressions in a moment, but first we -need to come up with the types Graph, Visitor, Vertex, -Index, and Color.

-
-
-

2.5.3   The binding Metafunction

-

To compute the type of a parameter we can use a Metafunction -called binding:

-
-binding<ArgumentPack, Keyword, Default = void>
-{ typedef see text type; };
-
-

where Default is the type of the default argument, if any.

-

For example, to declare and initialize g above, we could write:

-
-typedef typename parameter::binding<
-  ArgumentPack,tag::graph
->::type Graph;
-
-Graph g = args[graph];
-
-

As shown in the parameter table, graph has no default, so -the binding invocation for Graph takes only two arguments. -The default visitor is boost::dfs_visitor<>(), so the -binding invocation for Visitor takes three arguments:

-
-typedef typename parameter::binding<
-  ArgumentPack,tag::visitor,boost::dfs_visitor<>
->::type Visitor;
-
-Visitor v = args[visitor|boost::dfs_visitor<>()];
-
-

Note that the default visitor is supplied as a temporary -instance of dfs_visitor. Because args[…] always yields -a reference, making v a reference would cause it to bind to -that temporary, and immediately dangle. Therefore, it's crucial -that we passed dfs_visitor<>, and not dfs_visitor<> -const&, as the last argument to binding.

-
-

Important

-

Never pass binding a reference type as the default unless -you know that the default value passed to the ArgumentPack's -indexing operator will outlive the reference you'll bind to it.

-
-

Sometimes there's no need to use binding at all. The -root_vertex argument is required to be of the graph's -vertex_descriptor type,3 so we can just -use that knowledge to bypass binding altogether.

-
-typename boost::graph_traits<Graph>::vertex_descriptor
-  s = args[root_vertex|*vertices(g).first];
-
-
-
-

2.5.4   Beyond Ordinary Default Arguments

-

Here's how you might write the declaration for the index_map -parameter:

-
-typedef typename parameter::binding<
-    ArgumentPack
-  , tag::index_map
-  , typename boost::property_map<Graph, vertex_index_t>::const_type
->::type Index;
-
-Index i = args[index_map|get(boost::vertex_index,g)];
-
-

Notice two capabilities we've gained over what -plain C++ default arguments provide:

-
    -
  1. The default value of the index parameter depends on the -value of the graph parameter. That's illegal in plain C++:

    -
    -void f(int graph, int index = graph + 1); // error
    -
    -
  2. -
  3. The index parameter has a useful default, yet it is -templated and its type can be deduced when an index -argument is explicitly specified by the caller. In plain C++, you -can specify a default value for a parameter with deduced type, -but it's not very useful:

    -
    -template <class Index>
    -int f(Index index = 42);  // OK
    -int y = f();                // error; can't deduce Index
    -
    -
  4. +

    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. +
    3. The name of the resulting function template.
    4. +
    5. The name of a namespace where we can find tag types whose names +match the function's parameter names.
    6. +
    7. The function signature.
+
+

2.1.5   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.

+
+

2.1.5.1   Required Parameters

+
+

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:

+
+(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.

-
-

2.6   Syntactic Refinement

-

In this section we'll describe how you can allow callers to invoke -depth_first_search with just one pair of parentheses, and to -omit keywords where appropriate.

-
-

2.6.1   Describing the Positional Argument Order

-

First, we'll need to build a type that describes the allowed -parameters and their ordering when passed positionally. This type -is known as a ParameterSpec (MSVC6.x users see this note):

+
+
+

2.1.5.2   Optional Parameters

+
+

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:

+
+(optional ⁣
+    (visitor,           *, boost::dfs_visitor<>())
+    (root_vertex,       *, *vertices(graph).first)
+    (index_map,         *, get(boost::vertex_index,graph))
+    (in_out(color_map), *,
+      default_color_map(num_vertices(graph), index_map) )
+)
+
+
+
+
+

2.1.5.3   Handling “Out” Parameters

+
+

Within the function body, a parameter name such as visitor is +a C++ reference, bound either to an actual argument passed by +the caller or to the result of evaluating a default expression. +In most cases, parameter types are of the form T const& for +some T. Parameters whose values are expected to be modified, +however, must be passed by reference to non-const. To +indicate that color_map is both read and written, we wrap +its name in in_out(…):

+
+(optional
+    (visitor,            *, boost::dfs_visitor<>())
+    (root_vertex,        *, *vertices(graph).first)
+    (index_map,          *, get(boost::vertex_index,graph))
+    (in_out(color_map), *,
+      default_color_map(num_vertices(graph), index_map) )
+)
+
+
+

If color_map were strictly going to be modified but not examined, +we could have written out(color_map). There is no functional +difference between out and in_out; the library provides +both so you can make your interfaces more self-documenting.

+
+
+

2.1.5.4   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

-namespace graphs
+graphs::depth_first_search(x, y);
+
+

x will always be interpreted as a graph and y will always +be interpreted as a visitor.

+
+
+

2.1.5.5   Default Expression Evaluation

+
+

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.

+
+(required (graph, *) )
+(optional
+  (visitor,           *, boost::dfs_visitor<>())
+  (root_vertex,       *, *vertices(graph).first)
+  (index_map,         *, get(boost::vertex_index,graph))
+  (in_out(color_map), *,
+    default_color_map(num_vertices(graph), index_map) )
+)
+
+

A default expression is evaluated in the context of all preceding +parameters, so you can use any of their values by name.

+
+
+

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:

+
+#include <boost/graph/depth_first_search.hpp> // for dfs_visitor
+
+BOOST_PARAMETER_FUNCTION(
+    (void), depth_first_search, graphs
+    …signature goes here…
+)
 {
-  typedef parameter::parameters<
-      tag::graph
-    , tag::visitor
-    , tag::root_vertex
-    , tag::index_map
-    , tag::color_map
-  > dfs_params;
+   std::cout << "graph=" << graph << std::endl;
+   std::cout << "visitor=" << visitor << std::endl;
+   std::cout << "root_vertex=" << root_vertex << std::endl;
+   std::cout << "index_map=" << index_map << std::endl;
+   std::cout << "color_map=" << color_map << std::endl;
+}
+
+int main()
+{
+    depth_first_search(1, 2, 3, 4, 5);
+
+    depth_first_search(
+        "1", '2', color_map = '5',
+        visitor = "4", root_vertex = "3");
 }
 
-

The parameters template supplies a function-call -operator that groups all its arguments into an ArgumentPack. Any -arguments passed to it without a keyword label will be associated -with a parameter according to its position in the ParameterSpec. -So for example, given an object p of type dfs_params,

-
-p('G', index_map=1)
-
-

yields an ArgumentPack whose graph parameter has a value of -'G', and whose index_map parameter has a value of 1.

+

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.

-
-

2.6.2   Forwarding Functions

-

Next we need a family of overloaded depth_first_search function -templates that can be called with anywhere from one to five -arguments. These forwarding functions will invoke an instance of -dfs_params as a function object, passing their parameters -to its operator() and forwarding the result on to -core::depth_first_search:

+
+
+

2.1.5.6   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. +
  3. 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).4
  4. +
  5. 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 +types7, but suppose we want it to found via ADL?
  6. +
+

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 consider +what happens when we add this (admittedly contrived) overload:

-namespace graphs
-{
-  template <class A0>
-  void depth_first_search(A0 const& a0)
-  {
-     core::depth_first_search(dfs_params()(a0));
-  }
+// new overload
+template <class G>
+void depth_first_search(G const&, int, std::string);
+…
+// ambiguous!
+depth_first_search(boost::adjacency_list<>(), 2, "hello");
+
+
+
2.1.5.6.1   Adding Type 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 need to tell +the library about this requirement by replacing the * element +of the signature with the required type, in parentheses:

+
+(root_vertex,
+     (typename boost::graph_traits<graph_type>::vertex_descriptor),
+     *vertices(graph).first)
+
+

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.

+
+

Note

+

The type of the graph argument is available in the +signature—and in the function body—as graph_type. In +general, to access the type of any parameter foo, write foo_type.

+
+
+
+
2.1.5.6.2   Predicate Requirements
+

The requirements on other arguments are a bit more interesting than +those on root_vertex; they can't be described in terms of simple +type matching. Instead, they must be described in terms of MPL +Metafunctions. There's no space to give a complete description +of metafunctions or of graph library details here, but we'll show +you the complete signature with maximal checking, just to give you +a feel for how it's done. Each predicate metafunction is enclosed +in parentheses and preceded by an asterix, as follows:

+
+BOOST_PARAMETER_FUNCTION(
+    (void), depth_first_search, graphs
 
-  template <class A0, class A1>
-  void depth_first_search(A0 const& a0, A1 const& a1)
-  {
-     core::depth_first_search(dfs_params()(a0,a1));
-  } 
-  .
-  .
-  .
- 
-  template <class A0, class A1, …class A4>
-  void depth_first_search(A0 const& a0, A1 const& a1, …A4 const& a4)
-  {
-     core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4));
-  }
-}
-
-

That's it! We can now call graphs::depth_first_search with -from one to five arguments passed positionally or via keyword.

-
-
-

2.6.3   “Out” Parameters

-

Well, that's not quite it. When passing arguments by keyword, -the keyword object's assignment operator yields a temporary -ArgumentPack object. A conforming C++ compiler will refuse to -bind a non-const reference to a temporary, so to support a -keyword interface for all arguments, the overload set above must -take its arguments by const reference. On the other hand—as -you may recall from the parameter tablecolor_map is an -“out” parameter, so it really should be passed by non-const -reference.

-

A keyword object has a pair of operator= overloads that ensure -we can pass anything—temporary or not, const or not—by name, -while preserving the mutability of non-temporaries:

-
-template <class A>                  // handles non-const, 
-ArgumentPack operator=(A&);       // non-temporary objects
+  , (required
+      (graph
+       , *(boost::mpl::and_<
+               boost::is_convertible<
+                   boost::graph_traits<G>::traversal_category,
+                 , boost::incidence_graph_tag
+               >
+             , boost::is_convertible<
+                   boost::graph_traits<G>::traversal_category,
+                 , boost::vertex_list_graph_tag
+               >
+           >) ))
 
-template <class A>                  // handles const objects
-ArgumentPack operator=(A const&); // and temporaries
-
-

However, when an “out” parameter is passed positionally, there's no -keyword object involved. With our depth_first_search overload -set above, the color_map will be passed by const reference, -and compilation will fail when mutating operations are used on it. -The simple solution is to add another overload that takes a -non-const reference in the position of the “out” parameter:

-
-template <class A0, class A1, …class A4>
-void depth_first_search(A0 const& a0, A1 const& a1, …A4& a4)
-{
-    core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4));
-}
-
-

That approach works nicely because there is only one “out” -parameter and it is in the last position. If color_map had -been the first parameter, we would have needed ten overloads. In -the worst case—where the function has five “out” parameters—25 or 32 overloads would be required. This “forwarding -problem” is well-known to generic library authors, and the C++ -standard committee is working on a proposal to address it. In -the meantime, you might consider using Boost.Preprocessor to -generate the overloads you need.

-

If it is impractical for you to generate or write the overloads -that would be required for positional “out” arguments to be passed -directly, you still have the option to ask users to pass them -through boost::ref, which will ensure that the algorithm implementation -sees a non-const reference:

-
-depth_first_search(g, v, s, i, boost::ref(c));
-
-
-
-

2.6.4   Generating Forwarding Functions with Macros

-

To remove some of the tedium of writing overloaded forwarding -functions, the library supplies a macro, suitably located in -boost/parameter/macros.hpp, that will generate free function -overloads for you:

-
-BOOST_PARAMETER_FUN(void, depth_first_search, 1, 5, dfs_params);
-
-

will generate a family of five depth_first_search overloads, in -the current scope, that pass their arguments through -dfs_params. Instead of core::depth_first_search, these -overloads will forward the ArgumentPack on to a function called -depth_first_search_with_named_params, also in the current -scope. It's up to you to implement that function. You could -simply transplant the body of core::depth_first_search into -depth_first_search_with_named_params if you were going to use -this approach.

-

Note that BOOST_PARAMETER_FUN only takes arguments by const -reference, so you will have to add any additional overloads -required to handle positional “out” parameters yourself. We are -looking into providing a more sophisticated set of macros to -address this problem and others, for an upcoming release of Boost.

-
-
-
-

2.7   Controlling Overload Resolution

-

The parameters of our templated forwarding functions are completely -general; in fact, they're a perfect match for any argument type -whatsoever. The problems with exposing such general function -templates have been the subject of much discussion, especially in -the presence of unqualified calls. Probably the safest thing -to do is to isolate the forwarding functions in a namespace -containing no types5, but often we'd like our functions -to play nicely with argument-dependent lookup and other function -overloads. In that case, it's neccessary to remove the functions -from the overload set when the passed argument types aren't -appropriate.

-
-

2.7.1   Updating the ParameterSpec

-

This sort of overload control can be accomplished in C++ by taking -advantage of the SFINAE (Substitution Failure Is Not An Error) -rule.6 You can take advantage of the Parameter library's -built-in SFINAE support by using the following class templates in -your ParameterSpec:

-
-template< class KeywordTag, class Predicate = unspecified >
-struct required;
+    (optional
+      (visitor, *, boost::dfs_visitor<>()) // not checkable
 
-template< class KeywordTag, class Predicate = unspecified >
-struct optional;
-
-

Instead of using keyword tags directly, we can wrap them in -required and optional to indicate which function parameters -are required, and optionally pass Predicates to describe the -type requirements for each function parameter. The Predicate -argument must be a unary MPL lambda expression that, when -applied to the actual type of the argument, indicates whether that -argument type meets the function's requirements for that parameter -position.

-

For example, let's say we want to restrict depth_first_search() so that -the graph parameter is required and the root_vertex -parameter is convertible to int. We might write:

-
-#include <boost/type_traits/is_convertible.hpp>
-#include <boost/mpl/placeholders.hpp>
-namespace graphs
-{
-  using namespace boost::mpl::placeholders;
+      (root_vertex
+        , (typename boost::graph_traits<graph_type>::vertex_descriptor)
+        , *vertices(graph).first)
 
-  struct dfs_params
-    : parameter::parameters<
-          parameter::required<tag::graph>
-        , parameter::optional<tag::visitor>
-        , parameter::optional<
-              tag::root_vertex, boost::is_convertible<_,int>
-          >
-        , parameter::optional<tag::index_map>
-        , parameter::optional<tag::color_map>
-      >
-  {};
-}
-
-
-
-

2.7.2   Applying SFINAE to the Overload Set

-

Now we add a special defaulted argument to each of our -depth_first_search overloads:

-
-namespace graphs
-{
-  template <class A0>
-  void depth_first_search(
-      A0 const& a0
-    , typename dfs_params::match<A0>::type p = dfs_params())
-  {
-     core::depth_first_search(p(a0));
-  }
+      (index_map
+        , *(boost::mpl::and_<
+              boost::is_integral<
+                  boost::property_traits<index_map_type>::value_type
+              >
+            , boost::is_same<
+                  typename boost::graph_traits<graph_type>::vertex_descriptor
+                , boost::property_traits<index_map_type>::key_type
+              >
+          >)
+        , get(boost::vertex_index,graph))
 
-  template <class A0, class A1>
-  void depth_first_search(
-      A0 const& a0, A1 const& a1
-    , typename dfs_params::match<A0,A1>::type p = dfs_params())
-  {
-     core::depth_first_search(p(a0,a1));
-  } 
-  .
-  .
-  .
- 
-  template <class A0, class A1, …class A4>
-  void depth_first_search(
-      A0 const& a0, A1 const& a1, …A4 const& A4
-    , typename dfs_params::match<A0,A1,A2,A3,A4>::type p = dfs_params())
-  {
-     core::depth_first_search(p(a0,a1,a2,a3,a4));
-  }
-}
+      (in_out(color_map)
+        , *(boost::is_same<
+              typename boost::graph_traits<graph_type>::vertex_descriptor
+            , boost::property_traits<index_map_type>::key_type
+          >)
+       , default_color_map(num_vertices(graph), index_map) )
+    )
+)
 
-

These additional parameters are not intended to be used directly by -callers; they merely trigger SFINAE by becoming illegal types when -the root_vertex argument is not convertible to int. The -BOOST_PARAMETER_FUN macro described earlier adds these extra -function parameters for you (Borland users see this note).

+

We acknowledge that this signature is pretty hairy looking. +Fortunately, it usually isn't necessary to so completely encode the +type requirements on arguments to generic functions. However, it +is usally worth the effort to do so: your code will be more +self-documenting and will often provide a better user experience. +You'll also have an easier transition to an upcoming C++ standard +with language support for concepts.

-
-

2.7.3   Reducing Boilerplate With Macros

-

The library provides a macro you can use to eliminate some of the -repetetiveness of the declaring the optional parameters. -BOOST_PARAMETER_MATCH takes three arguments: the -ParameterSpec, a Boost.Preprocessor sequence of the function -argument types, and a name for the defaulted function parameter -(p, above), and it generates the appropriate defaulted -argument. So we could shorten the overload set definition as +

+
+

2.1.5.7   Deduced Parameters

+

To illustrate deduced parameter support we'll have to leave behind +our example from the Graph library. Instead, consider the example +of the def function from Boost.Python. Its signature is +roughly as follows:

+
+template <
+  class Function, Class KeywordExpression, class 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()
+);
+
+

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:

-namespace graphs
-{
-  template <class A0>
-  void depth_first_search(
-      A0 const& a0
-    , BOOST_PARAMETER_MATCH(dfs_params, (A0), p))
-  {
-     core::depth_first_search(p(a0));
-  }
+namespace mpl = boost::mpl;
 
-  template <class A0, class A1>
-  void depth_first_search(
-      A0 const& a0, A1 const& a1
-    , BOOST_PARAMETER_MATCH(dfs_params, (A0)(A1), p))
-  {
-     core::depth_first_search(p(a0,a1));
-  } 
-  .
-  .
-  .
- 
-  template <class A0, class A1, …class A4>
-  void depth_first_search(
-      A0 const& a0, A1 const& a1, …A4 const& A4
-    , BOOST_PARAMETER_MATCH(dfs_params, (A0)(A1)…(A4), p))
-  {
-     core::depth_first_search(p(a0,a1,a2,a3,a4));
-  }
+BOOST_PARAMETER_FUNCTION(
+    (void), def, tag
+
+    (required (name,(char const*)) (func,*) )   // nondeduced
+
+    (deduced
+      (optional
+        (docstring, (char const*), "")
+
+        (keywords
+           , *(is_keyword_expression<keywords_type>) // see6
+           , no_keywords())
+
+        (policies
+           , *(mpl::not_<
+                 mpl::or_<
+                     boost::is_convertible<policies_type, char const*>
+                   , is_keyword_expression<policies_type> // see6
+                 >
+             >)
+           , default_call_policies()
+         )
+       )
+     )
+ )
+ {
+    
+ }
+
+
+

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:

+
+def("f", f, some_policies, "Documentation for f");
+def("f", f, "Documentation for f", some_policies);
+
+

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:

+
+def(
+    "f", f
+   , _policies = some_policies, "Documentation for f");
+
+
+
+
+
+

2.2   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), operator(), (required (arg1,(int))(arg2,(int))))
+    {
+        std::cout << arg1 << ", " << arg2 << std::endl;
+    }
+};
+
+

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), operator(), (required (arg1,(int))(arg2,(int))))
+    {
+        call_impl(arg1,arg2);
+    }
+ private:
+    void call_impl(int, int); // implemented elsewhere.
+};
+
+
+
+

2.3   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 a base class.

+

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 <class ArgumentPack>
+    myclass_impl(ArgumentPack const& args)
+    {
+        std::cout << "name = " << args[_name]
+                  << "; index = " << args[_index | 42]
+                  << std::endl;
+    }
+};
+
+

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
+
+

For more on ArgumentPack manipulation, see the Advanced Topics +section.

+
+
+

2.4   Parameter-Enabled Class Templates

+

In this section we'll use Boost.Parameter to build Boost.Python's class_ template, whose “signature” is:

+
+template class<
+    ValueType, BaseList = bases<>
+  , HeldType = ValueType, Copyable = void
+>
+class class_;
+
+

Only the first argument, ValueType, is required.

+
+

2.4.1   Named Template Parameters

+

First, we'll build an interface that allows users to pass arguments +positionally or by name:

+
+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> >
+> …;
+
+
+

2.4.1.1   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);
+
+}}
+
+

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 <class T>
+struct class_type
+  : parameter::template_keyword<tag::class_type,T>
+{};
+
+}}
+
+

It defines a keyword tag type named tag::class_type and a +parameter passing template named class_type.

+
+
+

2.4.1.2   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:

+
+namespace boost { namespace python {
+
+template <
+    class A0
+  , class A1 = parameter::void_
+  , class A2 = parameter::void_
+  , class A3 = parameter::void_
+>
+struct class_
+{
+    
+};
+
+}}
+
+
+
+

2.4.1.3   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, is_class<_> >
+  , optional<tag::base_list, mpl::is_sequence<_> >
+  , optional<tag::held_type>
+  , optional<tag::copyable>
+> class_signature;
+
+}}
+
+
+
+

2.4.1.4   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 binding< + > metafunction to extract “logical parameters”. Note that +defaults are specified by supplying an optional third argument to +binding< >:

+
+namespace boost { namespace python {
+
+template <
+    class A0
+  , class A1 = parameter::void_
+  , class A2 = parameter::void_
+  , class A3 = parameter::void_
+>
+struct class_
+{
+    // Create ArgumentPack
+    typedef typename
+      class_signature::bind<A0,A1,A2,A3>::type
+    args;
+
+    // Extract first logical parameter.
+    typedef typename parameter::binding<
+      args, tag::class_type>::type class_type;
+
+    typedef typename parameter::binding<
+      args, tag::base_list, bases<> >::type base_list;
+
+    typedef typename parameter::binding<
+      args, tag::held_type, class_type>::type held_type;
+
+    typedef typename parameter::binding<
+      args, tag::copyable, void>::type copyable;
+};
+
+}}
+
+
+
+
+

2.4.2   Exercising the Code So Far

+
+

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;
+
+

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>));
+
+
+
+
+

2.4.3   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:

+
+namespace boost { namespace python {
+
+namespace detail { struct bases_base {}; }
+
+template <class A0 = void, class A1 = void, class A2 = void  >
+struct bases : bases_base
+{};
+
+}}
+
+

Now we can rewrite our signature to make all three optional +parameters deducible:

+
+typedef parameter::parameters<
+    required<tag::class_type, is_class<_> >
+
+  , optional<
+        deduced<tag::base_list>
+      , is_base_and_derived<bases_base,_>
+    >
+
+  , optional<
+        deduced<tag::held_type>
+      , mpl::not_<
+            mpl::or_<
+                is_base_and_derived<bases_base,_>
+              , is_same<noncopyable,_>
+            >
+        >
+    >
+
+  , optional<deduced<tag::copyable>, is_same<noncopyable,_> >
+
+> class_signature;
+
+

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:

+
+typedef boost::python::class_<B, boost::noncopyable> c1;
+
+typedef boost::python::class_<D, std::auto_ptr<D>, bases<B> > c2;
+
+
+
+
+
+

3   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.

+
+

3.1   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:

+
+BOOST_PARAMETER_NAME((object-name, tag-namespace) parameter-name)
+
+

Here is a usage example:

+
+BOOST_PARAMETER_NAME((pass_foo, keywords) foo)
+
+BOOST_PARAMETER_FUNCTION(
+  (int), f,
+  keywords, (required (foo, *)))
+{
+    return foo + 1;
+}
+
+int x = f(pass_foo = 41);
+
+

Before you use this more verbose form, however, please read the +section on best practices for keyword object naming.

+
+
+

3.2   More ArgumentPacks

+

We've already seen ArgumentPacks when we looked at +parameter-enabled constructors and class templates. As you +might have guessed, ArgumentPacks actually lie at the heart of +everything this library does; in this section we'll examine ways to +build and manipulate them more effectively.

+
+

3.2.1   Building ArgumentPacks

+

The simplest ArgumentPack is the result of assigning into a +keyword object:

+
+BOOST_PARAMETER_NAME(index)
+
+template <class ArgumentPack>
+int print_index(ArgumentPack const& args)
+{
+    std::cout << "index = " << args[_index] << std::endl;
+    return 0;
+}
+
+int x = print_index(_index = 3);  // prints "index = 3"
+
+

Also, ArgumentPacks 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 <class ArgumentPack>
+int print_name_and_index(ArgumentPack const& args)
+{
+    std::cout << "name = " << args[_name] << "; ";
+    return print_index(args);
+}
+
+int y = print_name_and_index((_index = 3, _name = "jones"));
+
+

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:

+
+parameter::parameters<
+    required<tag::name, is_convertible<_,char const*> >
+  , optional<tag::index, is_convertible<_,int> >
+> const spec;
+
+int z0 = print_name_and_index( spec("sam", 12) );
+
+int z1 = print_name_and_index(
+   spec(_index=12, _name="sam")
+);
+
+
+
+

3.2.2   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 <class Name, class Index>
+void deduce_arg_types_impl(Name& name, Index& index)
+{
+    Name& n2 = name;  // we know the types
+    Index& i2 = index;
+}
+
+template <class ArgumentPack>
+int deduce_arg_types(ArgumentPack const& args)
+{
+    deduce_arg_types_impl(args[_name], args[_index|42]);
 }
 
-
-
-
-

2.8   Efficiency Issues

-

The color_map parameter gives us a few efficiency issues to -consider. Here's a first cut at extraction and binding:

+

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 binding< > metafunction introduced +earlier:

-typedef 
-  vector_property_map<boost::default_color_type, Index>
-default_color_map;
+BOOST_PARAMETER_NAME(index)
+
+template <class ArgumentPack>
+typename parameter::binding<ArgumentPack, tag::index, int>::type
+twice_index(ArgumentPack const& args)
+{
+    return 2 * args[_index|42]);
+}
+
+int six = twice_index(_index = 3);
+
+
+
+

3.2.3   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 ArgumentPacks explicitly, we need a tool other than +operator|:

+
+BOOST_PARAMETER_NAME(s1)
+BOOST_PARAMETER_NAME(s2)
+BOOST_PARAMETER_NAME(s3)
+
+template <class 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"));
+
+

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 combining the logical-or (“``||``”) operator +with a function object built by the Boost Lambda library:5

+
+namespace lambda = boost::lambda;
 
 typename parameter::binding<
-    ArgumentPack
-  , tag::color_map
-  , default_color_map
->::type color = args[color_map|default_color_map(num_vertices(g),i)];
-
-
-

2.8.1   Eliminating Copies

-

The library has no way to know whether an explicitly-supplied -argument is expensive to copy (or even if it is copyable at all), -so binding<…,k,…>::type is always a reference type when the -k parameter is supplied by the caller. Since args[…] -yields a reference to the actual argument, color will be bound -to the actual color_map argument and no copying will be done.

-

As described above, because the default is a temporary, it's -important that color be a non-reference when the default is -used. In that case, the default value will be copied into -color. If we store the default in a named variable, though, -color can be a reference, thereby eliminating the copy:

-
-default_color_map default_color(num_vertices(g),i);
-
-typename parameter::binding<
-    ArgumentPack
-  , tag::color_map
-  , default_color_map&
->::type color = args[color_map|default_color];
-
-
-

Hint

-

To avoid making needless copies, pass a reference to the -default type as the third argument to binding.

-
-
-
-

2.8.2   Lazy Default Computation

-

Of course it's nice to avoid copying default_color, but the -more important cost is that of constructing it in the first -place. A vector_property_map is cheap to copy, since it holds -its elements via a shared_ptr. On the other hand, construction of -default_color costs at least two dynamic memory allocations and -num_vertices(g) copies; it would be better to avoid doing this -work when the default value won't be needed.

-

To that end, the library allows us to supply a callable object -that—if no argument was supplied by the caller—will be invoked to -construct the default value. Instead of following the keyword with -the | operator, we'll use || and follow it with a -nullary (zero-argument) function object that constructs a -default_color_map. Here, we build the function object using -Boost.Lambda:4

-
-// After #include <boost/lambda/construct.hpp>
-typename parameter::binding<
-    ArgumentPack
-  , tag::color_map
-  , default_color_map
->::type color = args[
-  color_map
-  || boost::lambda::construct<default_color_map>(num_vertices(g),i)
-];
+    ArgumentPack, tag::s3, std::string
+>::type s3 = args[_s3 || (lambda::var(s1)+lambda::var(s2)) ];
 
+

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.

-
-

2.8.3   Default Forwarding

-

Types that are expensive to construct yet cheap to copy aren't all -that typical, and even copying the color map is more expensive than -we might like. It might be nice to avoid both needless -construction and needless copying of the default color map. The -simplest way to achieve that is to avoid naming it altogether, at -least not in core::depth_first_search. Instead, we'll -introduce another function template to implement the actual -algorithm:

+
+
+
+

4   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.

+
+

4.1   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:

-namespace graphs { namespace core
+namespace people
 {
-  template <class G, class V, class S, class I, class C>
-  void dfs_impl(G& g, V& v, S& s, I& i, C& c)
-  {
-      …actual algorithm implementation…
-  }
-}}
-
-

Then, in core::depth_first_search, we'll simply forward the -result of indexing args to core::dfs_impl:

-
-core::dfs_impl( 
-    g,v,s,i
-  , args[
-      color_map
-      || boost::lambda::construct<default_color_map>(num_vertices(g),i)
-    ]);
-
-

In real code, after going to the trouble to write dfs_impl, -we'd probably just forward all the arguments.

-
-
-

2.8.4   Dispatching Based on the Presence of a Default

-

In fact, the Graph library itself constructs a slightly different -color_map, to avoid even the overhead of initializing a -shared_ptr:

-
-std::vector<boost::default_color_type> 
-  color_vec(num_vertices(g));
+  namespace tag { struct name; struct age;  }
 
-boost::iterator_property_map<
-    typename std::vector<
-       boost::default_color_type
-    >::iterator
-  , Index
-> c(color_vec.begin(), i);
+  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)
+  {
+       .
+     .
+     .
+   
+     g(age = 3); // whoops!
+  }
+}
 
-

To avoid instantiating that code when it isn't needed, we'll have -to find a way to select different function implementations, at -compile time, based on whether a color_map argument was -supplied. By using tag dispatching on the presence of a -color_map argument, we can do just that:

+

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 that 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.

+
+
+

4.2   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:

-#include <boost/type_traits/is_same.hpp>
-#include <boost/mpl/bool.hpp>
+namespace lib
+{
+  BOOST_PARAMETER_KEYWORD(name)
+  BOOST_PARAMETER_KEYWORD(index)
 
-namespace graphs { namespace core {
-
-  template <class ArgumentPack>
-  void dfs_dispatch(ArgumentPack& args, mpl::true_)
+  BOOST_PARAMETER_FUNCTION(
+    (int), f, tag,
+    (optional (name,*,"bob")(index,(int),1))
+  )
   {
-      …use the color map computed in the previous example…
+      std::cout << name << ":" << index << std::endl;
+      return index;
   }
-  
-  template <class ArgumentPack>
-  void dfs_dispatch(ArgumentPack& args, mpl::false_)
-  {
-      …use args[color]…
-  }
-  
-  template <class ArgumentPack>
-  void depth_first_search(ArgumentPack& args)
-  {
-      typedef typename binding<args,tag::color>::type color_;
-      core::dfs_dispatch(args, boost::is_same<color_,void>());
-  }
-}}
+}
 
-

We've used the fact that the default for binding's third -argument is void: because specializations of is_same are -bool-valued MPL Integral Constants derived either -from mpl::true_ or mpl::false_, the appropriate -dfs_dispatch implementation will be selected.

+

Users of these functions have a few choices:

+
    +
  1. Full qualification:
  2. +
+
+
+int x = lib::f(lib::_name = "jill", lib::_index = 1);
+
+

This approach is more verbose than many users would like.

+
+
    +
  1. Make keyword objects available through +using-declarations:
  2. +
+
+
+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.

+
+
    +
  1. Bring in the entire namespace with a using-directive:
  2. +
+
+
+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.

+
+

If we add an additional namespace around keyword declarations, +though, we can give users more control:

+
+namespace lib
+{
+  namespace keywords
+  {
+     BOOST_PARAMETER_KEYWORD(name)
+     BOOST_PARAMETER_KEYWORD(index)
+  }
+
+  BOOST_PARAMETER_FUNCTION(
+    (int), f, keywords::tag,
+    (optional (name,*,"bob")(index,(int),1))
+  )
+  {
+      std::cout << name << ":" << index << std::endl;
+      return index;
+  }
+}
+
+

Now users need only a single using-directive to bring in just the +names of all keywords associated with lib:

+
+using namespace lib::keywords;
+int y = lib::f(_name = "bob", _index = 2);
+
+
+
+

4.3   Documentation

+

The interface idioms enabled by Boost.Parameter are completely new +(to C++), and as such are not served by pre-existing documentation +conventions.

+
+write something here!!
-
-
-

3   Portability Considerations

+
+

5   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.

-
-

3.1   No SFINAE Support

+
+

5.1   No SFINAE Support

Some older compilers don't support SFINAE. If your compiler meets that criterion, then Boost headers will #define the preprocessor -symbol BOOST_NO_SFINAE, and uses of parameters<…>::match and -BOOST_PARAMETER_MATCH will be harmless, but will have no effect.

+symbol BOOST_NO_SFINAE, and parameter-enabled functions won't be +removed from the overload set based on their signatures.

-
-

3.2   No Support for result_of

+
+

5.2   No Support for 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 @@ -1046,32 +1495,37 @@ 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().

-
-
-

3.3   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++ +

-
-

3.5   Compiler Can't See References In Unnamed Namespace

+
+

5.3   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 @@ -1091,13 +1545,43 @@ namespace graphs

-
-

4   Reference

+
+

6   Reference

Follow this link to the Boost.Parameter reference documentation.

-
-

5   Acknowledgements

+
+

7   Glossary

+ +++ + + + + +
Argument (or “actual argument”):
 the value actually passed to a +function or class template
+ +++ + + + + +
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:

+
+int f(int x) { return x + 1 }
+int y = f(3);
+
+
+
+
+

8   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.

@@ -1115,7 +1599,7 @@ backward-compatibility. - @@ -1123,7 +1607,7 @@ units (object files) that make up a program.
[2]The One Definition Rule says that any given entity in +
[2]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.
-
[3]If you're not familiar with the Boost Graph +
[3]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 @@ -1131,42 +1615,48 @@ could replace all mentions of vertex descriptor types with library wouldn't suffer.
+ + + + + +
[4]This is a major motivation behind ConceptC++.
-
[4]

The Lambda library is known not to work on some +

[5]

The Lambda library is known not to work on some less-conformant compilers. When using one of those you could -define

+use Boost.Bind to generate the function object:

-  template <class T>
-  struct construct2
-  {
-      typedef T result_type;
-
-      template <class A1, class A2>
-      T operator()(A1 a1, A2 a2) { return T(a1,a2); }
-  };
-
-and use `Boost.Bind`_ to generate the function object::
-
-  boost::bind(construct2<default_color_map>(),num_vertices(g),i)
+boost::bind(std::plus<std::string>(),s1,s2)
 
+ + + + + +
[6](1, 2) 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.
- @@ -1174,24 +1664,30 @@ using foo_overloads::foo;
[5]

You can always give the illusion that the function +

[7]

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;  
+  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.
 
-
[6]If type substitution during the instantiation of a -function template results in an invalid type, no compilation -error is emitted; instead the overload is removed from the -overload set. By producing an invalid type in the function -signature depending on the result of some condition, whether or -not an overload is considered during overload resolution can be -controlled. The technique is formalized in the enable_if -utility. See +
[8]This capability depends on your compiler's support for SFINAE. +SFINAE: Substitution Failure Is +Not An 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.
- diff --git a/doc/index.rst b/doc/index.rst index 0deb82d..8925f36 100755 --- a/doc/index.rst +++ b/doc/index.rst @@ -11,16 +11,61 @@ __ ../../../../index.htm ------------------------------------- -:Abstract: Use this library to write functions that accept - arguments by name: +: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**); + new_window("alert", **_width=10**, **_titlebar=false**); + smart_ptr< + Foo + , **deleter >** + , **copy_policy** > p(new Foo); + 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. + 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 . /boost//headers ;''') + +.. @example.prepend(''' + #include + + namespace test + { + BOOST_PARAMETER_NAME(width) + BOOST_PARAMETER_NAME(titlebar) + + BOOST_PARAMETER_FUNCTION( + (int), new_window, tag, (required (width,*)(titlebar,*))) + { + return 0; + } + + BOOST_PARAMETER_TEMPLATE_KEYWORD(deleter) + BOOST_PARAMETER_TEMPLATE_KEYWORD(copy_policy) + + template struct Deallocate {}; + struct DeepCopy {}; + + namespace parameter = boost::parameter; + + struct Foo {}; + template + struct smart_ptr + { + smart_ptr(Foo*); + }; + } + using namespace test; + int x = '''); + +.. @build() + ------------------------------------- @@ -52,109 +97,154 @@ __ ../../../../index.htm ------------------------------------- -============== - Introduction -============== +============ + Motivation +============ -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: +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: -* 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: +* .. compound:: - .. parsed-literal:: + 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: - window* new_window( - char const* name, - **int border_width = default_border_width,** - bool movable = true, - bool initially_visible = true - ); + .. parsed-literal:: - const bool movability = false; - window* w = new_window("alert box", movability); + window* new_window( + char const* name, + **int border_width = default_border_width,** + bool movable = true, + bool initially_visible = true + ); - 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: + const bool movability = false; + window* w = new_window("alert box", movability); - .. parsed-literal:: + 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: - window* w = new_window( - "alert box", **default_border_width**, movability); + .. 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:: +* .. compound:: - window* w = new_window("alert", 1, true, false); + It can become difficult for readers to understand the meaning of + arguments at the call site:: - Is this window moveable and initially invisible, or unmoveable - and initially visible? The reader needs to remember the order - of arguments to be sure. + 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:: +------------------------- +Named Function Parameters +------------------------- - window* w = new_window("alert box", **movable=**\ false); // OK! +.. compound:: -.. 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: + 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: - C++ has two other limitations, with respect to default arguments, - that are unrelated to its positional interface: + .. parsed-literal:: - * Default values cannot depend on the values of other function - parameters: + window* w = new_window("alert box", **movable_=**\ false); // OK! - .. parsed-literal:: +--------------------------- +Deduced Function Parameters +--------------------------- - // Can we make resize windows to a square shape by default? - void resize( - window* w, - int **width**, - int height **= width** // nope, error! - ); +.. compound:: - * Default values in function templates are useless for any - argument whose type should be deduced when the argument is - supplied explicitly:: + 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: - template - void f(T x = 0); + .. parsed-literal:: - f(3.14) // ok: x supplied explicitly; T is double - f(); // error: can't deduce T from default argument 0! + window* w = new_window(movable_=false, **"alert box"**); // OK! + window* w = new_window(**"alert box"**, movable_=false); // OK! - As a side effect of using the Boost Parameter library, you may find - that you circumvent both of these limitations quite naturally. + Appropriately used, a deduced parameter interface can free the + user of the burden of even remembering the formal parameter + names. + +-------------------------------- +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**, **value_type** > 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``). 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; ========== 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]_ 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. +|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/index.html @@ -211,787 +301,1119 @@ shown in the table below. .. 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. | - +----------------+----------+----------------------------------+ + +----------------+----------+---------------------------------+----------------------------------+ + | Parameter Name | Dataflow | Type | Default Value (if any) | + +================+==========+=================================+==================================+ + |``graph`` | in |Model of |IncidenceGraph|_ and |none - this argument is required. | + | | ||VertexListGraph|_ | | + | | | | | + +----------------+----------+---------------------------------+----------------------------------+ + |``visitor`` | in |Model of |DFSVisitor|_ |``boost::dfs_visitor<>()`` | + +----------------+----------+---------------------------------+----------------------------------+ + |``root_vertex`` | in |``graph``'s vertex descriptor |``*vertices(graph).first`` | + | | |type. | | + +----------------+----------+---------------------------------+----------------------------------+ + |``index_map`` | in |Model of |ReadablePropertyMap|_ |``get(boost::vertex_index,graph)``| + | | |with key type := ``graph``'s | | + | | |vertex descriptor and value type | | + | | |an integer type. | | + +----------------+----------+---------------------------------+----------------------------------+ + |``color_map`` | in/out |Model of |ReadWritePropertyMap|_ |an ``iterator_property_map`` | + | | |with key type := ``graph``'s |created from a ``std::vector`` of | + | | |vertex descriptor type. |``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. +.. |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 keyword arguments, leaving out any +``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**); + 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 +“\ ``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**. -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__):: +.. Revisit this - #include + 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 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) + 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) } -__ `Compiler Can't See References In Unnamed Namespace`_ -The declaration of the ``visitor`` keyword you see here is +The declaration of the ``graph`` keyword you see here is equivalent to:: namespace graphs { - namespace tag { struct visitor; } - namespace { - boost::parameter::keyword& visitor - = boost::parameter::keyword::get(); + namespace tag { struct graph; } // keyword tag type + + namespace // unnamed + { + // A reference to the keyword object + boost::parameter::keyword& _graph + = boost::parameter::keyword::instance; } } -This “fancy dance” involving the unnamed namespace and references +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. +units (MSVC6.x users see `this note`__). -Defining the Implementation Function -==================================== +__ `Compiler Can't See References In Unnamed Namespace`_ -Next we can write the skeleton of the function that implements -the core of ``depth_first_search``:: - - namespace graphs { namespace core - { - template - 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 - 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 - 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 - or, if no argument is passed explicitly, to the specified - default value. - -Getting More Realistic ----------------------- - -Now it's time to put some more realistic defaults in place. We'll -have to give up our print statements—at least if we want to see the -defaults work—since, the default values of these -parameters generally aren't printable. - -Instead, we'll connect local variables to the arguments and use -those in our algorithm: - -.. parsed-literal:: - - namespace graphs { namespace core - { - template - void depth_first_search(ArgumentPack const& args) - { - *Graph* g = args[graph]; - *Visitor* v = args[visitor|\ *default-expression*\ :sub:`1`\ ]; - *Vertex* s = args[root_vertex|\ *default-expression*\ :sub:`2`\ ]; - *Index* i = args[index_map|\ *default-expression*\ :sub:`3`\ ]; - *Color* c = args[visitor|\ *default-expression*\ :sub:`4`\ ]; - - *…use g, v, s, i, and c to implement the algorithm…* - } - }} // graphs::core - -We'll insert the `default expressions`_ in a moment, but first we -need to come up with the types *Graph*, *Visitor*, *Vertex*, -*Index*, and *Color*. - -The ``binding`` |Metafunction|_ -------------------------------- - -To compute the type of a parameter we can use a |Metafunction|_ -called ``binding``: - -.. parsed-literal:: - - binding - { typedef *see text* type; }; - -where ``Default`` is the type of the default argument, if any. - -For example, to declare and initialize ``g`` above, we could write: - -.. parsed-literal:: - - typedef typename parameter::binding< - ArgumentPack,\ **tag::graph** - >::type Graph; - - Graph g = args[graph]; - -As shown in the `parameter table`_, ``graph`` has no default, so -the ``binding`` invocation for *Graph* takes only two arguments. -The default ``visitor`` is ``boost::dfs_visitor<>()``, so the -``binding`` invocation for *Visitor* takes three arguments: - -.. parsed-literal:: - - typedef typename parameter::binding< - ArgumentPack,\ **tag::visitor,boost::dfs_visitor<>** - >::type Visitor; - - Visitor v = args[visitor|\ **boost::dfs_visitor<>()**\ ]; - -Note that the default ``visitor`` is supplied as a *temporary* -instance of ``dfs_visitor``. Because ``args[…]`` always yields -a reference, making ``v`` a reference would cause it to bind to -that temporary, and immediately dangle. Therefore, it's crucial -that we passed ``dfs_visitor<>``, and not ``dfs_visitor<> -const&``, as the last argument to ``binding``. - -.. Important:: - - Never pass ``binding`` a reference type as the default unless - you know that the default value passed to the |ArgumentPack|\ 's - indexing operator will outlive the reference you'll bind to it. - -Sometimes there's no need to use ``binding`` at all. The -``root_vertex`` argument is required to be of the graph's -``vertex_descriptor`` type, [#vertex_descriptor]_ so we can just -use that knowledge to bypass ``binding`` altogether. - -.. parsed-literal:: - - typename **boost::graph_traits::vertex_descriptor** - s = args[root_vertex|\ ***vertices(g).first**\ ]; - -.. _dangling: - -.. |Metafunction| replace:: :concept:`Metafunction` - -.. _Metafunction: ../../../mpl/doc/refmanual/metafunction.html - -Beyond Ordinary Default Arguments ---------------------------------- - -Here's how you might write the declaration for the ``index_map`` -parameter: - -.. parsed-literal:: - - typedef typename parameter::binding< - ArgumentPack - , tag::index_map - , **typename boost::property_map::const_type** - >::type Index; - - Index i = args[index_map|\ **get(boost::vertex_index,g)**\ ]; - -Notice two capabilities we've gained over what -plain C++ default arguments provide: - -1. The default value of the ``index`` parameter depends on the - value of the ``graph`` parameter. That's illegal in plain C++: - - .. parsed-literal:: - - void f(int **graph**, int index = **graph** + 1); // error - -2. The ``index`` parameter has a useful default, yet it is - templated and its type can be deduced when an ``index`` - argument is explicitly specified by the caller. In plain C++, you - can *specify* a default value for a parameter with deduced type, - but it's not very useful: - - .. parsed-literal:: - - template - int f(Index index **= 42**); // OK - int y = f(); // **error; can't deduce Index** - -Syntactic Refinement +Writing the Function ==================== -In this section we'll describe how you can allow callers to invoke -``depth_first_search`` with just one pair of parentheses, and to -omit keywords where appropriate. +Now that we have our keywords defined, the function template +definition follows a simple pattern using the +``BOOST_PARAMETER_FUNCTION`` macro:: - -Describing the Positional Argument Order ----------------------------------------- - -.. _ParameterSpec: - -.. |ParameterSpec| replace:: :concept:`ParameterSpec` - -First, we'll need to build a type that describes the allowed -parameters and their ordering when passed positionally. This type -is known as a |ParameterSpec| (MSVC6.x users see this note__):: + #include namespace graphs { - typedef parameter::parameters< - tag::graph - , tag::visitor - , tag::root_vertex - , tag::index_map - , tag::color_map - > dfs_params; + 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)) + (in_out(color_map), *, + default_color_map(num_vertices(graph), index_map) ) + ) + ) + { + // ... body of function goes here... + // use graph, visitor, index_map, and color_map + } } -__ `Can't Declare ParameterSpec Via typedef`_ +The arguments to ``BOOST_PARAMETER_FUNCTION`` are: -The ``parameters`` template supplies a function-call -operator that groups all its arguments into an |ArgumentPack|. Any -arguments passed to it without a keyword label will be associated -with a parameter according to its position in the |ParameterSpec|. -So for example, given an object ``p`` of type ``dfs_params``, :: +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. - p('G', index_map=1) +2. The name of the resulting function template. -yields an |ArgumentPack| whose ``graph`` parameter has a value of -``'G'``, and whose ``index_map`` parameter has a value of ``1``. +3. The name of a namespace where we can find tag types whose names + match the function's parameter names. -Forwarding Functions +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/index.html + +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. + +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)) + (in_out(color_map), \*, + default_color_map(num_vertices(graph), index_map) )** + ) + +Handling “Out” Parameters +------------------------- + +.. compound:: + + Within the function body, a parameter name such as ``visitor`` is + a *C++ reference*, bound either to an actual argument passed by + the caller or to the result of evaluating a default expression. + In most cases, parameter types are of the form ``T const&`` for + some ``T``. Parameters whose values are expected to be modified, + however, must be passed by reference to *non*\ -``const``. To + indicate that ``color_map`` is both read and written, we wrap + its name in ``in_out(…)``: + + .. parsed-literal:: + + (optional + (visitor, \*, boost::dfs_visitor<>()) + (root_vertex, \*, \*vertices(graph).first) + (index_map, \*, get(boost::vertex_index,graph)) + (**in_out(color_map)**, \*, + default_color_map(num_vertices(graph), index_map) ) + ) + +If ``color_map`` were strictly going to be modified but not examined, +we could have written ``out(color_map)``. There is no functional +difference between ``out`` and ``in_out``; the library provides +both so you can make your interfaces more self-documenting. + +Positional Arguments -------------------- - -Next we need a family of overloaded ``depth_first_search`` function -templates that can be called with anywhere from one to five -arguments. These *forwarding functions* will invoke an instance of -``dfs_params`` as a function object, passing their parameters -to its ``operator()`` and forwarding the result on to -``core::depth_first_search``: -.. parsed-literal:: +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 :: - namespace graphs - { - template - void depth_first_search(A0 const& a0) + graphs::depth_first_search(x, y); + +``x`` will always be interpreted as a graph and ``y`` will always +be interpreted as a visitor. + +.. _sequence: http://boost-consulting.com/mplbook/preprocessor.html#sequences + +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**)) + (in_out(color_map), \*, + default_color_map(num_vertices(**graph**), index_map) ) + ) + + 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 // for dfs_visitor + + BOOST_PARAMETER_FUNCTION( + (void), depth_first_search, graphs + *…signature goes here…* + ) { - core::depth_first_search(dfs_params()(a0)); + std::cout << "graph=" << graph << std::endl; + std::cout << "visitor=" << visitor << std::endl; + std::cout << "root_vertex=" << root_vertex << std::endl; + std::cout << "index_map=" << index_map << std::endl; + std::cout << "color_map=" << color_map << std::endl; } - template - void depth_first_search(A0 const& a0, A1 const& a1) + int main() { - core::depth_first_search(dfs_params()(a0,a1)); - } :vellipsis:`\ - . - . - . -  ` - template - void depth_first_search(A0 const& a0, A1 const& a1, …A4 const& a4) - { - core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4)); + depth_first_search(1, 2, 3, 4, 5); + + depth_first_search( + "1", '2', color_map = '5', + visitor = "4", root_vertex = "3"); } - } -That's it! We can now call ``graphs::depth_first_search`` with -from one to five arguments passed positionally or via keyword. + 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. -“Out” Parameters ----------------- +Signature Matching and Overloading +---------------------------------- -Well, that's not *quite* it. When passing arguments by keyword, -the keyword object's assignment operator yields a temporary -|ArgumentPack| object. A conforming C++ compiler will refuse to -bind a non-``const`` reference to a temporary, so to support a -keyword interface for all arguments, the overload set above *must* -take its arguments by ``const`` reference. On the other hand—as -you may recall from the `parameter table`_\ —\ ``color_map`` is an -“out” parameter, so it really should be passed by *non-*\ ``const`` -reference. +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. -A keyword object has a pair of ``operator=`` overloads that ensure -we can pass anything—temporary or not, ``const`` or not—by name, -while preserving the mutability of non-temporaries: +There are at least three problems with very general function +signatures. -.. parsed-literal:: +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. - template // handles non-const, - |ArgumentPack| operator=(A&); // non-temporary objects +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). [#ConceptCpp]_ - template // handles const objects - |ArgumentPack| operator=(A const&); // and temporaries - -However, when an “out” parameter is passed positionally, there's no -keyword object involved. With our ``depth_first_search`` overload -set above, the ``color_map`` will be passed by ``const`` reference, -and compilation will fail when mutating operations are used on it. -The simple solution is to add another overload that takes a -non-``const`` reference in the position of the “out” parameter: - -.. parsed-literal:: - - template - void depth_first_search(A0 **const&** a0, A1 **const&** a1, …\ A4\ **&** a4) - { - core::depth_first_search(dfs_params()(a0,a1,a2,a3,a4)); - } - -That approach works nicely because there is only one “out” -parameter and it is in the last position. If ``color_map`` had -been the first parameter, we would have needed *ten* overloads. In -the worst case—where the function has five “out” parameters—2\ -:sup:`5` or 32 overloads would be required. This “\ `forwarding -problem`_\ ” is well-known to generic library authors, and the C++ -standard committee is working on a proposal__ to address it. In -the meantime, you might consider using `Boost.Preprocessor`_ to -generate the overloads you need. - -.. _`forwarding problem`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm - -__ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html - -.. _`Boost.Preprocessor`: ../../../preprocessor - -If it is impractical for you to generate or write the overloads -that would be required for positional “out” arguments to be passed -directly, you still have the option to ask users to pass them -through |ref|_, which will ensure that the algorithm implementation -sees a non-``const`` reference: - -.. parsed-literal:: - - depth_first_search(g, v, s, i, **boost::ref(c)**); - -.. |ref| replace:: ``boost::ref`` - -.. _ref: http://www.boost.org/doc/html/reference_wrapper.html - -Generating Forwarding Functions with Macros -------------------------------------------- - -To remove some of the tedium of writing overloaded forwarding -functions, the library supplies a macro, suitably located in -``boost/parameter/macros.hpp``, that will generate free function -overloads for you:: - - BOOST_PARAMETER_FUN(void, depth_first_search, 1, 5, dfs_params); - -will generate a family of five ``depth_first_search`` overloads, in -the current scope, that pass their arguments through -``dfs_params``. Instead of ``core::depth_first_search``, these -overloads will forward the |ArgumentPack| on to a function called -``depth_first_search_with_named_params``, also in the current -scope. It's up to you to implement that function. You could -simply transplant the body of ``core::depth_first_search`` into -``depth_first_search_with_named_params`` if you were going to use -this approach. - -Note that ``BOOST_PARAMETER_FUN`` only takes arguments by ``const`` -reference, so you will have to add any additional overloads -required to handle positional “out” parameters yourself. We are -looking into providing a more sophisticated set of macros to -address this problem and others, for an upcoming release of Boost. - -Controlling Overload Resolution -=============================== - -The parameters of our templated forwarding functions are completely -general; in fact, they're a perfect match for any argument type -whatsoever. The problems with exposing such general function -templates have been the subject of much discussion, especially in -the presence of `unqualified calls`__. Probably the safest thing -to do is to isolate the forwarding functions in a namespace -containing no types [#using]_, but often we'd *like* our functions -to play nicely with argument-dependent lookup and other function -overloads. In that case, it's neccessary to remove the functions -from the overload set when the passed argument types aren't -appropriate. +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://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#225 -Updating the |ParameterSpec| ----------------------------- +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:: -This sort of overload control can be accomplished in C++ by taking -advantage of the SFINAE (Substitution Failure Is Not An Error) -rule. [#sfinae]_ You can take advantage of the Parameter library's -built-in SFINAE support by using the following class templates in -your |ParameterSpec|: - -.. parsed-literal:: - - template< class KeywordTag, class Predicate = *unspecified* > - struct required; - - template< class KeywordTag, class Predicate = *unspecified* > - struct optional; - -Instead of using keyword tags directly, we can wrap them in -``required`` and ``optional`` to indicate which function parameters -are required, and optionally pass ``Predicate``\ s to describe the -type requirements for each function parameter. The ``Predicate`` -argument must be a unary `MPL lambda expression`_ that, when -applied to the actual type of the argument, indicates whether that -argument type meets the function's requirements for that parameter -position. - -.. _`MPL lambda expression`: ../../../mpl/doc/refmanual/lambda-expression.html - -For example, let's say we want to restrict ``depth_first_search()`` so that -the ``graph`` parameter is required and the ``root_vertex`` -parameter is convertible to ``int``. We might write: - -.. parsed-literal:: - - #include - #include - namespace graphs + // new overload + BOOST_PARAMETER_FUNCTION( + (void), depth_first_search, (tag), (required (graph,*))( … )) { - using namespace boost::mpl::placeholders; - - struct dfs_params - : parameter::parameters< - **parameter::required** - , parameter::optional - , **parameter::optional< - tag::root_vertex, boost::is_convertible<_,int> - >** - , parameter::optional - , parameter::optional - > - {}; + // new algorithm implementation } -Applying SFINAE to the Overload Set ------------------------------------ + … -Now we add a special defaulted argument to each of our -``depth_first_search`` overloads: + // ambiguous! + depth_first_search(boost::adjacency_list<>(), 2, "hello"); + +Adding Type 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 need to tell +the library about this requirement by replacing the ``*`` element +of the signature with the required type, in parentheses: + +__ `parameter table`_ .. parsed-literal:: - namespace graphs - { - template - void depth_first_search( - A0 const& a0 - , typename dfs_params::match::type p = dfs_params()) - { - core::depth_first_search(**p**\ (a0)); - } + (root_vertex, + **(typename boost::graph_traits::vertex_descriptor)**, + \*vertices(graph).first) - template - void depth_first_search( - A0 const& a0, A1 const& a1 - , typename dfs_params::match::type p = dfs_params()) - { - core::depth_first_search(**p**\ (a0,a1)); - } :vellipsis:`\ - . - . - . -  ` - template - void depth_first_search( - A0 const& a0, A1 const& a1, …A4 const& A4 - , typename dfs_params::match::type p = dfs_params()) - { - core::depth_first_search(**p**\ (a0,a1,a2,a3,a4)); - } - } +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. + +.. Note:: The *type* of the ``graph`` argument is available in the + signature—and in the function body—as ``graph_type``. In + general, to access the type of any parameter *foo*, write *foo*\ + ``_type``. -These additional parameters are not intended to be used directly by -callers; they merely trigger SFINAE by becoming illegal types when -the ``root_vertex`` argument is not convertible to ``int``. The -``BOOST_PARAMETER_FUN`` macro described earlier adds these extra -function parameters for you (Borland users see this note__). +Predicate Requirements +...................... -.. _BOOST_PARAMETER_MATCH: - -__ `Default Arguments Unsupported on Nested Templates`_ - -Reducing Boilerplate With Macros --------------------------------- - -The library provides a macro you can use to eliminate some of the -repetetiveness of the declaring the optional parameters. -``BOOST_PARAMETER_MATCH`` takes three arguments: the -|ParameterSpec|, a `Boost.Preprocessor sequence`__ of the function -argument types, and a name for the defaulted function parameter -(``p``, above), and it generates the appropriate defaulted -argument. So we could shorten the overload set definition as -follows: - -__ http://boost-consulting.com/mplbook/preprocessor.html#sequences +The requirements on other arguments are a bit more interesting than +those on ``root_vertex``; they can't be described in terms of simple +type matching. Instead, they must be described in terms of `MPL +Metafunctions`__. There's no space to give a complete description +of metafunctions or of graph library details here, but we'll show +you the complete signature with maximal checking, just to give you +a feel for how it's done. Each predicate metafunction is enclosed +in parentheses *and preceded by an asterix*, as follows: .. parsed-literal:: - namespace graphs - { - template - void depth_first_search( - A0 const& a0 - , **BOOST_PARAMETER_MATCH(dfs_params, (A0), p)**) - { - core::depth_first_search(p(a0)); - } + BOOST_PARAMETER_FUNCTION( + (void), depth_first_search, graphs - template - void depth_first_search( - A0 const& a0, A1 const& a1 - , **BOOST_PARAMETER_MATCH(dfs_params, (A0)(A1), p)**) - { - core::depth_first_search(p(a0,a1)); - } :vellipsis:`\ - . - . - . -  ` - template - void depth_first_search( - A0 const& a0, A1 const& a1, …A4 const& A4 - , **BOOST_PARAMETER_MATCH(dfs_params, (A0)(A1)…(A4), p)**) - { - core::depth_first_search(p(a0,a1,a2,a3,a4)); - } - } + , (required + (graph + , **\ \*(boost::mpl::and_< + boost::is_convertible< + boost::graph_traits::traversal_category, + , boost::incidence_graph_tag + > + , boost::is_convertible< + boost::graph_traits::traversal_category, + , boost::vertex_list_graph_tag + > + >)** )) -Efficiency Issues -================= + (optional + (visitor, \*, boost::dfs_visitor<>()) // not checkable -The ``color_map`` parameter gives us a few efficiency issues to -consider. Here's a first cut at extraction and binding: + (root_vertex + , (typename boost::graph_traits::vertex_descriptor) + , \*vertices(graph).first) + + (index_map + , **\ \*(boost::mpl::and_< + boost::is_integral< + boost::property_traits::value_type + > + , boost::is_same< + typename boost::graph_traits::vertex_descriptor + , boost::property_traits::key_type + > + >)** + , get(boost::vertex_index,graph)) + + (in_out(color_map) + , **\ \*(boost::is_same< + typename boost::graph_traits::vertex_descriptor + , boost::property_traits::key_type + >)** + , default_color_map(num_vertices(graph), index_map) ) + ) + ) -.. parsed-literal:: +__ ../../../mpl/doc/refmanual/metafunction.html - typedef - vector_property_map - default_color_map; +We acknowledge that this signature is pretty hairy looking. +Fortunately, it usually isn't necessary to so completely encode the +type requirements on arguments to generic functions. However, it +is usally worth the effort to do so: your code will be more +self-documenting and will often provide a better user experience. +You'll also have an easier transition to an upcoming C++ standard +with `language support for concepts`__. - typename parameter::binding< - ArgumentPack - , tag::color_map - , default_color_map - >::type color = args[color_map|\ **default_color_map(num_vertices(g),i)**\ ]; +__ `ConceptC++`_ -Eliminating Copies +Deduced Parameters ------------------ -The library has no way to know whether an explicitly-supplied -argument is expensive to copy (or even if it is copyable at all), -so ``binding<…,k,…>::type`` is always a reference type when the -*k* parameter is supplied by the caller. Since ``args[…]`` -yields a reference to the actual argument, ``color`` will be bound -to the actual ``color_map`` argument and no copying will be done. +To illustrate deduced parameter support we'll have to leave behind +our example from the Graph library. Instead, consider the example +of the |def|_ function from Boost.Python_. Its signature is +roughly as follows:: -As described above__, because the default is a temporary, it's -important that ``color`` be a non-reference when the default is -used. In that case, the default value will be *copied* into -``color``. If we store the default in a named variable, though, -``color`` can be a reference, thereby eliminating the copy: + template < + class Function, Class KeywordExpression, class 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() + ); + +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:: - default_color_map default_color(num_vertices(g),i); + namespace mpl = boost::mpl; - typename parameter::binding< - ArgumentPack - , tag::color_map - , **default_color_map&** - >::type color = args[color_map|default_color]; + BOOST_PARAMETER_FUNCTION( + (void), def, tag -__ dangling_ + (required (name,(char const\*)) (func,\*) ) // nondeduced -.. Hint:: + **(deduced** + (optional + (docstring, (char const\*), "") - To avoid making needless copies, pass a *reference to the - default type* as the third argument to ``binding``. + (keywords + , \*(is_keyword_expression) // see [#is_keyword_expression]_ + , no_keywords()) + + (policies + , \*(mpl::not_< + mpl::or_< + boost::is_convertible + , is_keyword_expression // see [#is_keyword_expression]_ + > + >) + , default_call_policies() + ) + ) + **)** + ) + { + *…* + } + +.. 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:: + + def("f", f, **some_policies**, **"Documentation for f"**); + def("f", f, **"Documentation for f"**, **some_policies**); + +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", f + , **_policies = some_policies**, "Documentation for f"); + +.. _Boost.Python: ../../../python/doc/index.html +.. |def| replace:: ``def`` +.. _def: ../../../python/doc/v2/def.html + +---------------------------------- +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), operator(), (required (arg1,(int))(arg2,(int)))) + { + std::cout << arg1 << ", " << arg2 << std::endl; + } + }; + +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), operator(), (required (arg1,(int))(arg2,(int)))) + { + call_impl(arg1,arg2); + } + private: + void call_impl(int, int); // implemented elsewhere. + }; + +------------------------------ +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 a base class. + +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 + myclass_impl(ArgumentPack const& args) + { + std::cout << "name = " << args[_name] + << "; index = " << args[_index | 42] + << std::endl; + } + }; + +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 + +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 class< + ValueType, BaseList = bases<> + , HeldType = ValueType, Copyable = void + > + class class\_; + +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**, **copyable** + > …; + + class_< + **D**, **held_type >**, **base_list >** + > …; + +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) + + }} + +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 + struct class_type + : parameter::template_keyword + {}; + + }} + +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 < + class A0 + , class A1 = parameter::void\_ + , class A2 = parameter::void\_ + , class A3 = parameter::void\_ + > + struct class\_ + { + *…* + }; + + }} + +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 > + , optional > + , optional + , optional + > class_signature; + + }} + +.. |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 ``binding< +… >`` metafunction to extract “logical parameters”. Note that +defaults are specified by supplying an optional third argument to +``binding< … >``:: + + namespace boost { namespace python { + + template < + class A0 + , class A1 = parameter::void_ + , class A2 = parameter::void_ + , class A3 = parameter::void_ + > + struct class_ + { + // Create ArgumentPack + typedef typename + class_signature::bind::type + args; + + // Extract first logical parameter. + typedef typename parameter::binding< + args, tag::class_type>::type class_type; + + typedef typename parameter::binding< + args, tag::base_list, bases<> >::type base_list; + + typedef typename parameter::binding< + args, tag::held_type, class_type>::type held_type; + + typedef typename parameter::binding< + 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, copyable + > c1; + + typedef boost::python::class_< + D, held_type >, base_list > + > c2; + + we can now examine the intended parameters:: + + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same >)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT(( + boost::is_same + )); + + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same >)); + BOOST_MPL_ASSERT(( + boost::is_same > + )); + BOOST_MPL_ASSERT((boost::is_same)); + +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 + struct bases **: bases_base** + {}; + + }} + +Now we can rewrite our signature to make all three optional +parameters deducible:: + + typedef parameter::parameters< + required > + + , optional< + deduced + , is_base_and_derived + > + + , optional< + deduced + , mpl::not_< + mpl::or_< + is_base_and_derived + , is_same + > + > + > + + , optional, is_same > + + > class_signature; + +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**, **bases** > c2; + +=============== +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*\ ) + +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); + +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 + int print_index(ArgumentPack const& args) + { + std::cout << "index = " << args[_index] << std::endl; + return 0; + } + + int x = print_index(_index = 3); // prints "index = 3" + +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 + int print_name_and_index(ArgumentPack const& args) + { + std::cout << "name = " << args[_name] << "; "; + return print_index(args); + } + + int y = print_name_and_index((_index = 3, _name = "jones")); + +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 > + , optional > + > const spec; + + int z0 = print_name_and_index( **spec(**\ "sam", 12\ **)** ); + + int z1 = print_name_and_index( + **spec(**\ _index=12, _name="sam"\ **)** + ); + +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 + void deduce_arg_types_impl(Name& name, Index& index) + { + Name& n2 = name; // we know the types + Index& i2 = index; + } + + template + int deduce_arg_types(ArgumentPack const& args) + { + deduce_arg_types_impl(args[_name], args[_index|42]); + } + +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 ``binding< … >`` metafunction introduced +`earlier`__:: + + BOOST_PARAMETER_NAME(index) + + template + typename parameter::binding::type + twice_index(ArgumentPack const& args) + { + return 2 * args[_index|42]); + } + + int six = twice_index(_index = 3); + +__ binding_intro_ Lazy Default Computation ------------------------- +======================== -Of course it's nice to avoid copying ``default_color``, but the -more important cost is that of *constructing* it in the first -place. A ``vector_property_map`` is cheap to copy, since it holds -its elements via a |shared_ptr|_. On the other hand, construction of -``default_color`` costs at least two dynamic memory allocations and -``num_vertices(g)`` copies; it would be better to avoid doing this -work when the default value won't be needed. +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|``:: -.. |shared_ptr| replace:: ``shared_ptr`` + BOOST_PARAMETER_NAME(s1) + BOOST_PARAMETER_NAME(s2) + BOOST_PARAMETER_NAME(s3) -.. _shared_ptr: ../../../smart_ptr/shared_ptr.htm + template + 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; + } -To that end, the library allows us to supply a callable object -that—if no argument was supplied by the caller—will be invoked to -construct the default value. Instead of following the keyword with -the ``|`` operator, we'll use ``||`` and follow it with a -nullary (zero-argument) function object that constructs a -default_color_map. Here, we build the function object using -Boost.Lambda_: [#bind]_ - -.. _Boost.Lambda: ../../../lambda/index.html + std::string x = f((_s1="hello,", _s2=" world", _s3="hi world")); + +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 combining the logical-or (“``||``”) operator +with a function object built by the Boost Lambda_ library: [#bind]_ .. parsed-literal:: - // After #include - typename parameter::binding< - ArgumentPack - , tag::color_map - , default_color_map - >::type color = args[ - color_map - **|| boost::lambda::construct(num_vertices(g),i)** - ]; + namespace lambda = boost::lambda; + + typename parameter::binding< + ArgumentPack, tag::s3, std::string + >::type s3 = args[_s3 **|| (lambda::var(s1)+lambda::var(s2))** ]; + +.. _Lambda: ../../../lambda/index.html .. sidebar:: Mnemonics @@ -1001,103 +1423,176 @@ Boost.Lambda_: [#bind]_ Similarly, in ``color_map[param||f]``, ``f`` is only invoked if no ``color_map`` argument was supplied. -Default Forwarding ------------------- +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. -Types that are expensive to construct yet cheap to copy aren't all -that typical, and even copying the color map is more expensive than -we might like. It might be nice to avoid both needless -construction *and* needless copying of the default color map. The -simplest way to achieve that is to avoid naming it altogether, at -least not in ``core::depth_first_search``. Instead, we'll -introduce another function template to implement the actual -algorithm: +================ + 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 graphs { namespace core + namespace people { - template - void **dfs_impl**\ (G& g, V& v, S& s, I& i, C& c) + namespace tag { struct name; struct age; } + + namespace // unnamed { - *…actual algorithm implementation…* + boost::parameter::keyword& **name** + = boost::parameter::keyword::instance; + boost::parameter::keyword& **age** + = boost::parameter::keyword::instance; } - }} -Then, in ``core::depth_first_search``, we'll simply forward the -result of indexing ``args`` to ``core::dfs_impl``:: + BOOST_PARAMETER_FUNCTION( + (void), g, tag, (optional (name, \*, "bob")(age, \*, 42))) + { + std::cout << name << ":" << age; + } - core::dfs_impl( - g,v,s,i - , args[ - color_map - || boost::lambda::construct(num_vertices(g),i) - ]); + void f(int age) + { + :vellipsis:`\ + . + . + . +  ` + g(**age** = 3); // whoops! + } + } -In real code, after going to the trouble to write ``dfs_impl``, -we'd probably just forward all the arguments. +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 that makes this problem less likely +to occur. -Dispatching Based on the Presence of a Default ----------------------------------------------- +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. -In fact, the Graph library itself constructs a slightly different -``color_map``, to avoid even the overhead of initializing a -|shared_ptr|_:: +---------- +Namespaces +---------- - std::vector - color_vec(num_vertices(g)); - - boost::iterator_property_map< - typename std::vector< - boost::default_color_type - >::iterator - , Index - > c(color_vec.begin(), i); - -To avoid instantiating that code when it isn't needed, we'll have -to find a way to select different function implementations, at -compile time, based on whether a ``color_map`` argument was -supplied. By using `tag dispatching`_ on the presence of a -``color_map`` argument, we can do just that: - -.. _`tag dispatching`: ../../../../more/generic_programming.html#tag_dispatching +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:: - #include - #include + namespace lib + { + **BOOST_PARAMETER_KEYWORD(name) + BOOST_PARAMETER_KEYWORD(index)** - namespace graphs { namespace core { + BOOST_PARAMETER_FUNCTION( + (int), f, tag, + (optional (name,*,"bob")(index,(int),1)) + ) + { + std::cout << name << ":" << index << std::endl; + return index; + } + } + +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. + +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. + +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. + +If we add an additional namespace around keyword declarations, +though, we can give users more control: + +.. parsed-literal:: + + namespace lib + { + **namespace keywords + {** + BOOST_PARAMETER_KEYWORD(name) + BOOST_PARAMETER_KEYWORD(index) + **}** + + BOOST_PARAMETER_FUNCTION( + (int), f, **keywords::**\ tag, + (optional (name,*,"bob")(index,(int),1)) + ) + { + std::cout << name << ":" << index << std::endl; + return index; + } + } + +Now users need only a single *using-directive* to bring in just the +names of all keywords associated with ``lib``: + +.. parsed-literal:: - template - void dfs_dispatch(ArgumentPack& args, **mpl::true_**) - { - *…use the color map computed in the previous example…* - } - - template - void dfs_dispatch(ArgumentPack& args, **mpl::false_**) - { - *…use args[color]…* - } - - template - void depth_first_search(ArgumentPack& args) - { - typedef typename binding::type color\_; - core::dfs_dispatch(args, **boost::is_same()**\ ); - } - }} + **using namespace lib::keywords;** + int y = lib::f(_name = "bob", _index = 2); -We've used the fact that the default for ``binding``\ 's third -argument is ``void``: because specializations of ``is_same`` are -``bool``-valued MPL |Integral Constant|_\ s derived either -from ``mpl::true_`` or ``mpl::false_``, the appropriate -``dfs_dispatch`` implementation will be selected. +------------- +Documentation +------------- -.. |Integral Constant| replace:: :concept:`Integral Constant` +The interface idioms enabled by Boost.Parameter are completely new +(to C++), and as such are not served by pre-existing documentation +conventions. -.. _`Integral Constant`: ../../../mpl/doc/refmanual/integral-constant.html + *write something here!!* ============================ Portability Considerations @@ -1110,16 +1605,18 @@ issues and workarounds for particular compilers. .. _`regression test results`: http://www.boost.org/regression/release/user/parameter.html +----------------- No SFINAE Support -================= +----------------- Some older compilers don't support SFINAE. If your compiler meets that criterion, then Boost headers will ``#define`` the preprocessor -symbol ``BOOST_NO_SFINAE``, and uses of ``parameters<…>::match`` and -|BOOST_PARAMETER_MATCH| will be harmless, but will have no effect. +symbol ``BOOST_NO_SFINAE``, and parameter-enabled functions won't be +removed from the overload set based on their signatures. +--------------------------- No Support for |result_of|_ -=========================== +--------------------------- .. |result_of| replace:: ``result_of`` @@ -1136,36 +1633,39 @@ 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`` -============================================= +.. + 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: + 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:: + .. parsed-literal:: - **struct dfs_parameters - :** parameter::parameters< - tag::graph, tag::visitor, tag::root_vertex - , tag::index_map, tag::color_map - > **{};** + **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. + Default Arguments Unsupported on Nested Templates + ================================================= -.. |BOOST_PARAMETER_MATCH| replace:: ``BOOST_PARAMETER_MATCH`` + 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 @@ -1195,6 +1695,25 @@ 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``:: + + int f(int x) { return x + 1 } + int y = f(3); + ================== Acknowledgements ================== @@ -1224,22 +1743,19 @@ __ ../../../graph/doc/bgl_named_params.html ``int`` in the text, and your understanding of the Parameter library wouldn't suffer. +.. [#ConceptCpp] This is a major motivation behind `ConceptC++`_. + +.. _`ConceptC++`: http://www.generic-programming.org/software/ConceptGCC/ + .. [#bind] The Lambda library is known not to work on `some less-conformant compilers`__. When using one of those you could - define :: - - template - struct construct2 - { - typedef T result_type; + use `Boost.Bind`_ to generate the function object:: - template - T operator()(A1 a1, A2 a2) { return T(a1,a2); } - }; + boost::bind(std::plus(),s1,s2) - and use `Boost.Bind`_ to generate the function object:: - - boost::bind(construct2(),num_vertices(g),i) +.. [#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: ../../../libs/bind/index.html @@ -1254,17 +1770,25 @@ __ http://www.boost.org/regression/release/user/lambda.html void foo() { ... } ... } - using foo_overloads::foo; + using foo_overloads::foo; + + This technique for avoiding unintentional argument-dependent + lookup is due to Herb Sutter. -.. [#sfinae] If type substitution during the instantiation of a - function template results in an invalid type, no compilation - error is emitted; instead the overload is removed from the - overload set. By producing an invalid type in the function - signature depending on the result of some condition, whether or - not an overload is considered during overload resolution can be - controlled. The technique is formalized in the |enable_if|_ - utility. See +.. [#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. From cb501f9f380a9ee8a46616bdd8c5672b69a79129 Mon Sep 17 00:00:00 2001 From: Daniel Wallin Date: Tue, 22 Aug 2006 17:36:58 +0000 Subject: [PATCH 12/58] merged changes from HEAD [SVN r34921] --- include/boost/parameter/preprocessor.hpp | 61 ++++++++++++++---------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/include/boost/parameter/preprocessor.hpp b/include/boost/parameter/preprocessor.hpp index bd6366d..1a594d9 100755 --- a/include/boost/parameter/preprocessor.hpp +++ b/include/boost/parameter/preprocessor.hpp @@ -523,15 +523,18 @@ T const& as_lvalue(T const& value, int) // Generates a keyword | default expression. # if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) -# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT(arg) \ - BOOST_PARAMETER_FN_ARG_KEYWORD(arg) | BOOST_PARAMETER_FN_ARG_DEFAULT(arg) +# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT(arg, tag_namespace) \ + boost::parameter::keyword< \ + tag_namespace::BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ + >::get() | BOOST_PARAMETER_FN_ARG_DEFAULT(arg) # else // For some reason, VC6 won't accept rvalues in this context. -# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT(arg) \ - BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ - | boost::parameter::aux::as_lvalue(BOOST_PARAMETER_FN_ARG_DEFAULT(arg), 0L) +# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT(arg, tag_namespace) \ + boost::parameter::keyword< \ + tag_namespace::BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ + >::get() | boost::parameter::aux::as_lvalue(BOOST_PARAMETER_FN_ARG_DEFAULT(arg), 0L) # endif -# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_BODY(name, n, split_args) \ +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_BODY(name, n, split_args, tag_namespace) \ { \ return BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ (ResultType(*)())0 \ @@ -547,6 +550,7 @@ T const& as_lvalue(T const& value, int) BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(4,2,split_args), n) \ , BOOST_PP_TUPLE_ELEM(4,3,split_args) \ ) \ + , tag_namespace \ ) \ ] \ ); \ @@ -569,32 +573,39 @@ T const& as_lvalue(T const& value, int) BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_TEMPLATE_ARG \ , n \ - , BOOST_PP_TUPLE_ELEM(3,1,data) \ + , BOOST_PP_TUPLE_ELEM(4,1,data) \ ) \ > \ - BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(BOOST_PP_TUPLE_ELEM(3,0,data)) \ - ResultType BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(BOOST_PP_TUPLE_ELEM(3,0,data))( \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(BOOST_PP_TUPLE_ELEM(4,0,data)) \ + ResultType BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(BOOST_PP_TUPLE_ELEM(4,0,data))( \ ResultType(*)() \ , Args const& args \ BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG \ , n \ - , BOOST_PP_TUPLE_ELEM(3,1,data) \ + , BOOST_PP_TUPLE_ELEM(4,1,data) \ ) \ - ) BOOST_PP_EXPR_IF(BOOST_PP_TUPLE_ELEM(3,2,data), const) \ + ) BOOST_PP_EXPR_IF(BOOST_PP_TUPLE_ELEM(4,2,data), const) \ BOOST_PP_IF( \ n \ , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_BODY \ - , ; BOOST_PP_TUPLE_EAT(3) \ - )(BOOST_PP_TUPLE_ELEM(3,0,data), n, BOOST_PP_TUPLE_ELEM(3,1,data)) + , ; BOOST_PP_TUPLE_EAT(4) \ + )( \ + BOOST_PP_TUPLE_ELEM(4,0,data) \ + , n \ + , BOOST_PP_TUPLE_ELEM(4,1,data) \ + , BOOST_PP_TUPLE_ELEM(4,3,data) \ + ) -# define BOOST_PARAMETER_FUNCTION_DEFAULT_GET_ARG(r, _, arg) \ - , args[BOOST_PARAMETER_FN_ARG_KEYWORD(arg)] +# define BOOST_PARAMETER_FUNCTION_DEFAULT_GET_ARG(r, tag_ns, arg) \ + , args[ \ + boost::parameter::keyword::get() \ + ] // Generates the function template that recives a ArgumentPack, and then // goes on to call the layers of overloads generated by // BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER. -# define BOOST_PARAMETER_FUNCTION_INITIAL_DISPATCH_FUNCTION(name, split_args, const_) \ +# define BOOST_PARAMETER_FUNCTION_INITIAL_DISPATCH_FUNCTION(name, split_args, const_, tag_ns) \ template \ typename BOOST_PARAMETER_FUNCTION_RESULT_NAME(name)::type \ BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(name) \ @@ -606,7 +617,7 @@ T const& as_lvalue(T const& value, int) \ BOOST_PP_SEQ_FOR_EACH( \ BOOST_PARAMETER_FUNCTION_DEFAULT_GET_ARG \ - , ~ \ + , tag_ns \ , BOOST_PP_TUPLE_ELEM(4,1,split_args) \ ) \ \ @@ -614,15 +625,17 @@ T const& as_lvalue(T const& value, int) } // Helper for BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER below. -# define BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER_AUX(name, split_args, skip_fwd_decl, const_) \ +# define BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER_AUX( \ + name, split_args, skip_fwd_decl, const_, tag_namespace \ + ) \ BOOST_PP_REPEAT_FROM_TO( \ skip_fwd_decl \ , BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4, 2, split_args)) \ , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION \ - , (name, split_args, const_) \ + , (name, split_args, const_, tag_namespace) \ ) \ \ - BOOST_PARAMETER_FUNCTION_INITIAL_DISPATCH_FUNCTION(name, split_args, const_) \ + BOOST_PARAMETER_FUNCTION_INITIAL_DISPATCH_FUNCTION(name, split_args, const_, tag_namespace) \ \ template < \ class ResultType \ @@ -646,9 +659,9 @@ T const& as_lvalue(T const& value, int) // Generates a bunch of forwarding functions that each extract // one more argument. -# define BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, skip_fwd_decl, const_) \ +# define BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, skip_fwd_decl, const_, tag_ns) \ BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER_AUX( \ - name, BOOST_PARAMETER_FUNCTION_SPLIT_ARGS(args), skip_fwd_decl, const_ \ + name, BOOST_PARAMETER_FUNCTION_SPLIT_ARGS(args), skip_fwd_decl, const_, tag_ns \ ) /**/ @@ -669,7 +682,7 @@ T const& as_lvalue(T const& value, int) , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ ) \ \ - BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, 0, 0) + BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, 0, 0, tag_namespace) // Defines a Boost.Parameter enabled function with the new syntax. # define BOOST_PARAMETER_FUNCTION(result, name, tag_namespace, args) \ @@ -737,7 +750,7 @@ T const& as_lvalue(T const& value, int) , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ ) \ \ - BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, 1, const_) + BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, 1, const_, tag_namespace) // Defines a Boost.Parameter enabled function with the new syntax. # define BOOST_PARAMETER_MEMBER_FUNCTION(result, name, tag_namespace, args) \ From 646c519dc0bde4ce53b1ba66c340e431342dc7dd Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 23 Aug 2006 13:01:56 +0000 Subject: [PATCH 13/58] merged from trunk [SVN r34930] --- doc/index.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index 8925f36..b1f0ecb 100755 --- a/doc/index.rst +++ b/doc/index.rst @@ -37,11 +37,12 @@ __ ../../../../index.htm namespace test { + BOOST_PARAMETER_NAME(title) BOOST_PARAMETER_NAME(width) BOOST_PARAMETER_NAME(titlebar) BOOST_PARAMETER_FUNCTION( - (int), new_window, tag, (required (width,*)(titlebar,*))) + (int), new_window, tag, (required (title,*)(width,*)(titlebar,*))) { return 0; } @@ -55,7 +56,7 @@ __ ../../../../index.htm namespace parameter = boost::parameter; struct Foo {}; - template + template struct smart_ptr { smart_ptr(Foo*); From 38817a8bb566c868b9c5c7993abef6293261744b Mon Sep 17 00:00:00 2001 From: Daniel Wallin Date: Thu, 24 Aug 2006 16:19:14 +0000 Subject: [PATCH 14/58] fixed missing include [SVN r34941] --- include/boost/parameter.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/parameter.hpp b/include/boost/parameter.hpp index 100ebf3..87d8542 100755 --- a/include/boost/parameter.hpp +++ b/include/boost/parameter.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #endif // BOOST_PARAMETER_050401_HPP From d6db8c6216291c121c7622a07b8a600d3a714099 Mon Sep 17 00:00:00 2001 From: Daniel Wallin Date: Thu, 24 Aug 2006 21:13:51 +0000 Subject: [PATCH 15/58] Merged name.hpp from HEAD. [SVN r34945] --- include/boost/parameter/name.hpp | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100755 include/boost/parameter/name.hpp diff --git a/include/boost/parameter/name.hpp b/include/boost/parameter/name.hpp new file mode 100755 index 0000000..4b9627a --- /dev/null +++ b/include/boost/parameter/name.hpp @@ -0,0 +1,87 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to 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) + +#ifndef BOOST_PARAMETER_NAME_060806_HPP +# define BOOST_PARAMETER_NAME_060806_HPP + +# include +# include +# include +# include +# include +# include +# include +# include + +# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# define BOOST_PARAMETER_NAME_OBJECT(tag, name) \ + static ::boost::parameter::keyword& name \ + = ::boost::parameter::keyword::get(); +# else +# define BOOST_PARAMETER_NAME_OBJECT(tag, name) \ + namespace \ + { \ + ::boost::parameter::keyword& name \ + = ::boost::parameter::keyword::get(); \ + } +# endif + +# define BOOST_PARAMETER_BASIC_NAME(tag_namespace, tag, name) \ + namespace tag_namespace \ + { \ + struct tag \ + { \ + static char const* keyword_name() \ + { \ + return BOOST_PP_STRINGIZE(tag); \ + } \ + }; \ + } \ + BOOST_PARAMETER_NAME_OBJECT(tag_namespace::tag, name) + +# define BOOST_PARAMETER_COMPLEX_NAME_TUPLE1(tag,namespace) \ + (tag, namespace), ~ + +# define BOOST_PARAMETER_COMPLEX_NAME_TUPLE(name) \ + BOOST_PP_TUPLE_ELEM(2, 0, (BOOST_PARAMETER_COMPLEX_NAME_TUPLE1 name)) + +# define BOOST_PARAMETER_COMPLEX_NAME_TAG(name) \ + BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PARAMETER_COMPLEX_NAME_TUPLE(name)) + +# define BOOST_PARAMETER_COMPLEX_NAME_NAMESPACE(name) \ + BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PARAMETER_COMPLEX_NAME_TUPLE(name)) + +# define BOOST_PARAMETER_COMPLEX_NAME(name) \ + BOOST_PARAMETER_BASIC_NAME( \ + BOOST_PARAMETER_COMPLEX_NAME_NAMESPACE(name) \ + , BOOST_PP_TUPLE_EAT(2) name \ + , BOOST_PARAMETER_COMPLEX_NAME_TAG(name) \ + ) \ +/**/ + +# define BOOST_PARAMETER_SIMPLE_NAME(name) \ + BOOST_PARAMETER_BASIC_NAME(tag, name, BOOST_PP_CAT(_, name)) + +# define BOOST_PARAMETER_NAME(name) \ + BOOST_PP_IIF( \ + BOOST_PP_IS_BINARY(name) \ + , BOOST_PARAMETER_COMPLEX_NAME \ + , BOOST_PARAMETER_SIMPLE_NAME \ + )(name) \ +/**/ + + +# define BOOST_PARAMETER_TEMPLATE_KEYWORD(name) \ + namespace tag \ + { \ + struct name; \ + } \ + template \ + struct name \ + : boost::parameter::template_keyword \ + {}; \ +/**/ + +#endif // BOOST_PARAMETER_NAME_060806_HPP + From 40399d3505d9315fd65413365a6bb11205ecfab5 Mon Sep 17 00:00:00 2001 From: nobody Date: Fri, 8 Sep 2006 09:38:01 +0000 Subject: [PATCH 16/58] This commit was manufactured by cvs2svn to create branch 'RC_1_34_0'. [SVN r35043] --- doc/python.rst | 771 +++++++++++++++++++++++++++++ test/normalized_argument_types.cpp | 83 ++++ 2 files changed, 854 insertions(+) create mode 100755 doc/python.rst create mode 100755 test/normalized_argument_types.cpp diff --git a/doc/python.rst b/doc/python.rst new file mode 100755 index 0000000..a9577a3 --- /dev/null +++ b/doc/python.rst @@ -0,0 +1,771 @@ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + The Boost Parameter Library Python Binding Documentation ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +:Authors: Daniel Wallin +:Contact: dalwan01@student.umu.se +:organization: `Boost Consulting`_ +:date: $Date$ + +: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) + +:abstract: Makes it possible to bind Boost.Parameter-enabled + functions, operators and constructors to Python. + +|(logo)|__ + +.. |(logo)| image:: ../../../../boost.png + :alt: Boost + +__ ../../../../index.htm + +.. _`Boost Consulting`: http://www.boost-consulting.com + + +.. role:: class + :class: class + +.. role:: concept + :class: concept + +.. role:: function + :class: function + +.. |ParameterSpec| replace:: :concept:`ParameterSpec` + +.. contents:: + :depth: 1 + +Introduction +------------ + +``boost/parameter/python.hpp`` introduces a group of |def_visitors|_ that can +be used to easily expose Boost.Parameter-enabled member functions to Python with +Boost.Python. It also provides a function template ``def()`` that can be used +to expose Boost.Parameter-enabled free functions. + +.. |def_visitor| replace:: ``def_visitor`` +.. |def_visitors| replace:: ``def_visitors`` + +.. _def_visitor: def_visitors_ +.. _def_visitors: ../../../python/doc/v2/def_visitor.html + +When binding a Boost.Parameter enabled function, the keyword tags +must be specified. Additionally, because Boost.Parameter enabled +functions are templates, the desired function signature must be +specified. + +.. The keyword tags are specified as an `MPL Sequence`_, using the + pointer qualifications described in |ParameterSpec|_ below. The + signature is also specifid as an `MPL sequence`_ of parameter + types. Additionally, ``boost::parameter::python::function`` and + ``boost::parameter::python::def`` requires a class with forwarding + overloads. We will take a closer look at how this is done in the + tutorial section below. + +The keyword tags and associated argument types are specified as an `MPL +Sequence`_, using the function type syntax described in |ParameterSpec|_ +below. Additionally, ``boost::parameter::python::function`` and +``boost::parameter::python::def`` requires a class with forwarding overloads. +We will take a closer look at how this is done in the tutorial section below. + +.. The last two sentences are terribly vague. Which namespace is +.. ``function`` in? Isn't the return type always needed? What +.. else are we going to do other than pass these sequences to +.. function? + +.. _`MPL Sequence`: ../../../mpl/doc/refmanual/sequences.html +.. _parameterspec: `concept ParameterSpec`_ + +Tutorial +-------- + +In this section we will outline the steps needed to bind a simple +Boost.Parameter-enabled member function to Python. Knowledge of the +Boost.Parameter macros_ are required to understand this section. + +.. _macros: index.html + +The class and member function we are interested in binding looks +like this: + +.. parsed-literal:: + + #include + #include + #include + #include + + // First the keywords + BOOST_PARAMETER_KEYWORD(tag, title) + BOOST_PARAMETER_KEYWORD(tag, width) + BOOST_PARAMETER_KEYWORD(tag, height) + + class window + { + public: + BOOST_PARAMETER_MEMBER_FUNCTION( + (void), open, tag, + (required (title, (std::string))) + (optional (width, (unsigned), 400) + (height, (unsigned), 400)) + ) + { + *… function implementation …* + } + }; + +.. @example.prepend('#include ') +.. @example.replace_emphasis(''' + assert(title == "foo"); + assert(height == 20); + assert(width == 400); + ''') + +It defines a set of overloaded member functions called ``open`` with one +required parameter and two optional ones. To bind this member function to +Python we use the binding utility ``boost::parameter::python::function``. +``boost::parameter::python::function`` is a |def_visitor|_ that we'll instantiate +and pass to ``boost::python::class_::def()``. + +To use ``boost::parameter::python::function`` we first need to define +a class with forwarding overloads. + +:: + + struct open_fwd + { + template + void operator()( + boost::type, window& self + , A0 const& a0, A1 const& a1, A2 const& a2 + ) + { + self.open(a0, a1, a2); + } + }; + +The first parameter, ``boost::type``, tells the forwarding overload +what the return type should be. In this case we know that it's always void +but in some cases, when we are exporting several specializations of a +Boost.Parameter-enabled template, we need to use that parameter to +deduce the return type. + +``window::open()`` takes a total of 3 parameters, so the forwarding function +needs to take three parameters as well. + +.. Note:: + + We only need one overload in the forwarding class, despite the + fact that there are two optional parameters. There are special + circumstances when several overload are needed; see + `special keywords`_. + +Next we'll define the module and export the class: + +:: + + BOOST_PYTHON_MODULE(my_module) + { + using namespace boost::python; + namespace py = boost::parameter::python; + namespace mpl = boost::mpl; + + class_("window") + .def( + "open", py::function< + open_fwd + , mpl::vector< + void + , tag::title(std::string) + , tag::width*(unsigned) + , tag::height*(unsigned) + > + >() + ); + } + +.. @jam_prefix.append('import python ;') +.. @jam_prefix.append('stage . : my_module /boost/python//boost_python ;') +.. @my_module = build( + output = 'my_module' + , target_rule = 'python-extension' + , input = '/boost/python//boost_python' + , howmany = 'all' + ) + +.. @del jam_prefix[:] + +``py::function`` is passed two parameters. The first one is the class with +forwarding overloads that we defined earlier. The second one is an `MPL +Sequence`_ with the keyword tag types and argument types for the function +specified as function types. The pointer syntax used in ``tag::width*`` and +``tag::height*`` means that the parameter is optional. The first element of +the `MPL Sequence`_ is the return type of the function, in this case ``void``. + +.. The + pointer syntax means that the parameter is optional, so in this case + ``width`` and ``height`` are optional parameters. The third parameter + is an `MPL Sequence`_ with the desired function signature. The return type comes first, and + then the parameter types: + + .. parsed-literal:: + + mpl::vector + *return type* *title* *width* *height* + + .. @ignore() + +That's it! This class can now be used in Python with the expected syntax:: + + >>> w = my_module.window() + >>> w.open(title = "foo", height = 20) + +.. @example.prepend('import my_module') +.. @run_python(module_path = my_module) + +.. Sorry to say this at such a late date, but this syntax really +.. strikes me as cumbersome. Couldn't we do something like: + + class_("window") + .def( + "open", + (void (*)( + tag::title(std::string), + tag::width*(unsigned), + tag::height*(unsigned)) + )0 + ); + + or at least: + + class_("window") + .def( + "open", + mpl::vector< + void, + tag::title(std::string), + tag::width*(unsigned), + tag::height*(unsigned) + >() + ); + + assuming, that is, that we will have to repeat the tags (yes, + users of broken compilers will have to give us function pointer + types instead). + +------------------------------------------------------------------------------ + +concept |ParameterSpec| +----------------------- + +A |ParameterSpec| is a function type ``K(T)`` that describes both the keyword tag, +``K``, and the argument type, ``T``, for a parameter. + +``K`` is either: + +* A *required* keyword of the form ``Tag`` +* **or**, an *optional* keyword of the form ``Tag*`` +* **or**, a *special* keyword of the form ``Tag**`` + +where ``Tag`` is a keyword tag type, as used in a specialization +of |keyword|__. + +.. |keyword| replace:: ``boost::parameter::keyword`` +__ ../../../parameter/doc/html/reference.html#keyword + +The **arity range** for an `MPL Sequence`_ of |ParameterSpec|'s is +defined as the closed range: + +.. parsed-literal:: + + [ mpl::size - number of *special* keyword tags in ``S``, mpl::size ] + +For example, the **arity range** of ``mpl::vector2`` is ``[2,2]``, +the **arity range** of ``mpl::vector2`` is ``[2,2]`` and the +**arity range** of ``mpl::vector2`` is ``[1,2]``. + + + +*special* keywords +--------------------------------- + +Sometimes it is desirable to have a default value for a parameter that differ +in type from the parameter. This technique is useful for doing simple tag-dispatching +based on the presence of a parameter. An example_ of this is given in the Boost.Parameter +docs. The example uses a different technique, but could also have been written like this: + +.. parsed-literal:: + + namespace core + { + template + void dfs_dispatch(ArgumentPack const& args, mpl::false\_) + { + *…compute and use default color map…* + } + + template + void dfs_dispatch(ArgumentPack const& args, ColorMap colormap) + { + *…use colormap…* + } + } + + template + void depth_first_search(ArgumentPack const& args) + { + core::dfs_dispatch(args, args[color | mpl::false_()]); + } + +.. @example.prepend(''' + #include + #include + #include + #include + + BOOST_PARAMETER_KEYWORD(tag, color); + + typedef boost::parameter::parameters params; + + namespace mpl = boost::mpl; + ''') + +.. @example.replace_emphasis(''' + assert(args[color | 1] == 1); + ''') + +.. @example.replace_emphasis(''' + assert(args[color | 1] == 0); + ''') + +.. @example.append(''' + int main() + { + depth_first_search(params()()); + depth_first_search(params()(color = 0)); + }''') + +.. @build() + +.. _example: index.html#dispatching-based-on-the-presence-of-a-default + +In the above example the type of the default for ``color`` is ``mpl::false_``, a +type that is distinct from any color map that the user might supply. + +When binding the case outlined above, the default type for ``color`` will not +be convertible to the parameter type. Therefore we need to tag the ``color`` +keyword as a *special* keyword. By doing this we tell the binding functions +that it needs to generate two overloads, one with the ``color`` parameter +present and one without. Had there been two *special* keywords, four +overloads would need to be generated. The number of generated overloads is +equal to 2\ :sup:`N`, where ``N`` is the number of *special* keywords. + +------------------------------------------------------------------------------ + +class template ``init`` +----------------------- + +Defines a named parameter enabled constructor. + +.. parsed-literal:: + + template + struct init : python::def_visitor > + { + template + void def(Class& class\_); + + template + *def\_visitor* operator[](CallPolicies const& policies) const; + }; + +.. @ignore() + +``init`` requirements +~~~~~~~~~~~~~~~~~~~~~ + +* ``ParameterSpecs`` is an `MPL sequence`_ where each element is a + model of |ParameterSpec|. +* For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity + range** of ``ParameterSpecs``, ``Class`` must support these + expressions: + + ======================= ============= ========================================= + Expression Return type Requirements + ======================= ============= ========================================= + ``Class(a0, …, aN)`` \- ``a0``\ …\ ``aN`` are tagged arguments. + ======================= ============= ========================================= + + + +``template operator[](CallPolicies const&)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns a ``def_visitor`` equivalent to ``*this``, except that it +uses CallPolicies when creating the binding. + + +Example +~~~~~~~ + +.. parsed-literal:: + + #include + #include + #include + #include + #include + + BOOST_PARAMETER_KEYWORD(tag, x) + BOOST_PARAMETER_KEYWORD(tag, y) + + struct base + { + template + base(ArgumentPack const& args) + { + *… use args …* + } + }; + + class X : base + { + public: + BOOST_PARAMETER_CONSTRUCTOR(X, (base), tag, + (required (x, \*)) + (optional (y, \*)) + ) + }; + + BOOST_PYTHON_MODULE(*module name*) + { + using namespace boost::python; + namespace py = boost::parameter::python; + namespace mpl = boost::mpl; + + class_("X", no_init) + .def( + py::init< + mpl::vector + >() + ); + } + +.. @example.replace_emphasis(''' + assert(args[x] == 0); + assert(args[y | 1] == 1); + ''') + +.. @example.replace_emphasis('my_module') + +.. @jam_prefix.append('import python ;') +.. @jam_prefix.append('stage . : my_module /boost/python//boost_python ;') +.. @my_module = build( + output = 'my_module' + , target_rule = 'python-extension' + , input = '/boost/python//boost_python' + ) + +------------------------------------------------------------------------------ + +class template ``call`` +----------------------- + +Defines a ``__call__`` operator, mapped to ``operator()`` in C++. + +.. parsed-literal:: + + template + struct call : python::def_visitor > + { + template + void def(Class& class\_); + + template + *def\_visitor* operator[](CallPolicies const& policies) const; + }; + +.. @ignore() + +``call`` requirements +~~~~~~~~~~~~~~~~~~~~~ + +* ``ParameterSpecs`` is an `MPL sequence`_ where each element + except the first models |ParameterSpec|. The first element + is the result type of ``c(…)``. +* ``Class`` must support these expressions, where ``c`` is an + instance of ``Class``: + + =================== ==================== ======================================= + Expression Return type Requirements + =================== ==================== ======================================= + ``c(a0, …, aN)`` Convertible to ``R`` ``a0``\ …\ ``aN`` are tagged arguments. + =================== ==================== ======================================= + + For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``ParameterSpecs``. + + +``template operator[](CallPolicies const&)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns a ``def_visitor`` equivalent to ``*this``, except that it +uses CallPolicies when creating the binding. + + +Example +~~~~~~~ + +.. parsed-literal:: + + #include + #include + #include + #include + #include + + BOOST_PARAMETER_KEYWORD(tag, x) + BOOST_PARAMETER_KEYWORD(tag, y) + + namespace parameter = boost::parameter; + + typedef parameter::parameters< + parameter::required + , parameter::optional + > call_parameters; + + class X + { + public: + template + int call_impl(ArgumentPack const& args) + { + *… use args …* + } + + template + int operator()(A0 const& a0) + { + return call_impl(call_parameters()(a0)); + } + + template + int operator()(A0 const& a0, A1 const& a1) + { + return call_impl(call_parameters()(a0,a1)); + } + }; + + BOOST_PYTHON_MODULE(*module name*) + { + using namespace boost::python; + namespace py = parameter::python; + namespace mpl = boost::mpl; + + class_("X") + .def( + py::call< + mpl::vector + >() + ); + } + +.. @example.replace_emphasis(''' + assert(args[x] == 0); + assert(args[y | 1] == 1); + return 0; + ''') + +.. @example.replace_emphasis('my_module') + +.. @my_module = build( + output = 'my_module' + , target_rule = 'python-extension' + , input = '/boost/python//boost_python' + ) + +------------------------------------------------------------------------------ + +class template ``function`` +--------------------------- + +Defines a named parameter enabled member function. + +.. parsed-literal:: + + template + struct function : python::def_visitor > + { + template + void def(Class& class\_, char const* name, Options const& options); + }; + +.. @ignore() + +``function`` requirements +~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``ParameterSpecs`` is an `MPL sequence`_ where each element + except the first models |ParameterSpec|. The first element + is the result type of ``c.f(…)``, where ``f`` is the member + function. +* An instance of ``Fwd`` must support this expression: + + ============================================ ==================== ================================================= + Expression Return type Requirements + ============================================ ==================== ================================================= + ``fwd(boost::type(), self, a0, …, aN)`` Convertible to ``R`` ``self`` is a reference to the object on which + the function should be invoked. ``a0``\ …\ ``aN`` + are tagged arguments. + ============================================ ==================== ================================================= + + For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``ParameterSpecs``. + + +Example +~~~~~~~ + +This example exports a member function ``f(int x, int y = …)`` to Python. The +sequence of |ParameterSpec|'s ``mpl::vector2`` has +an **arity range** of [2,2], so we only need one forwarding overload. + +.. parsed-literal:: + + #include + #include + #include + #include + #include + + BOOST_PARAMETER_KEYWORD(tag, x) + BOOST_PARAMETER_KEYWORD(tag, y) + + class X + { + public: + BOOST_PARAMETER_MEMBER_FUNCTION((void), f, tag, + (required (x, \*)) + (optional (y, \*, 1)) + ) + { + *…* + } + }; + + struct f_fwd + { + template + void operator()(boost::type, X& self, A0 const& a0, A1 const& a1) + { + self.f(a0, a1); + } + }; + + BOOST_PYTHON_MODULE(*module name*) + { + using namespace boost::python; + namespace py = boost::parameter::python; + namespace mpl = boost::mpl; + + class_("X") + .def("f", + py::function< + f_fwd + , mpl::vector + >() + ); + } + +.. @example.replace_emphasis(''' + assert(x == 0); + assert(y == 1); + ''') + +.. @example.replace_emphasis('my_module') + +.. @my_module = build( + output = 'my_module' + , target_rule = 'python-extension' + , input = '/boost/python//boost_python' + ) + +------------------------------------------------------------------------------ + +function template ``def`` +------------------------- + +Defines a named parameter enabled free function in the current Python scope. + +.. parsed-literal:: + + template + void def(char const* name); + +.. @ignore() + +``def`` requirements +~~~~~~~~~~~~~~~~~~~~ + +* ``ParameterSpecs`` is an `MPL sequence`_ where each element + except the first models |ParameterSpec|. The first element + is the result type of ``f(…)``, where ``f`` is the function. +* An instance of ``Fwd`` must support this expression: + + ====================================== ==================== ======================================= + Expression Return type Requirements + ====================================== ==================== ======================================= + ``fwd(boost::type(), a0, …, aN)`` Convertible to ``R`` ``a0``\ …\ ``aN`` are tagged arguments. + ====================================== ==================== ======================================= + + For every ``N`` in ``[U,V]``, where ``[U,V]`` is the **arity range** of ``ParameterSpecs``. + + +Example +~~~~~~~ + +This example exports a function ``f(int x, int y = …)`` to Python. The +sequence of |ParameterSpec|'s ``mpl::vector2`` has +an **arity range** of [2,2], so we only need one forwarding overload. + +.. parsed-literal:: + + BOOST_PARAMETER_FUNCTION((void), f, tag, + (required (x, \*)) + (optional (y, \*, 1)) + ) + { + *…* + } + + struct f_fwd + { + template + void operator()(boost::type, A0 const& a0, A1 const& a1) + { + f(a0, a1); + } + }; + + BOOST_PYTHON_MODULE(…) + { + def< + f_fwd + , mpl::vector< + void, tag::x(int), tag::y\*(int) + > + >("f"); + } + +.. @ignore() + +.. again, the undefined ``fwd`` identifier. + +Portability +----------- + +The Boost.Parameter Python binding library requires *partial template +specialization*. + diff --git a/test/normalized_argument_types.cpp b/test/normalized_argument_types.cpp new file mode 100755 index 0000000..260db69 --- /dev/null +++ b/test/normalized_argument_types.cpp @@ -0,0 +1,83 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to 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) + +#include +#include +#include +#include + +struct count_instances +{ + count_instances() + { + ++count; + } + + count_instances(count_instances const&) + { + ++count; + } + + template + count_instances(T const&) + { + ++count; + } + + ~count_instances() + { + --count; + } + + static std::size_t count; +}; + +std::size_t count_instances::count = 0; + +BOOST_PARAMETER_NAME(x) +BOOST_PARAMETER_NAME(y) + +BOOST_PARAMETER_FUNCTION((int), f, tag, + (required + (x, (int)) + (y, (int)) + ) +) +{ + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + return 0; +} + +BOOST_PARAMETER_FUNCTION((int), g, tag, + (required + (x, (count_instances)) + ) +) +{ + assert(count_instances::count == 1); + return 0; +} + +BOOST_PARAMETER_FUNCTION((int), h, tag, + (required + (x, (count_instances const&)) + ) +) +{ + assert(count_instances::count == 1); + return 0; +} + +int main() +{ + f(1, 2); + f(1., 2.f); + f(1U, 2L); + + g(0); + + h(0); +} + From e18d62150833976d267fb8388c27bc80ae94ac7c Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 11 Sep 2006 22:27:29 +0000 Subject: [PATCH 17/58] Add missing license/copyright [SVN r35070] --- doc/Jamfile.v2 | 3 +++ test/Jamfile | 4 ++++ test/Jamfile.v2 | 4 ++++ test/python.py | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 778d4ba..ae0636a 100755 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -1,3 +1,6 @@ +# Copyright David Abrahams 2006. 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) import docutils ; import path ; diff --git a/test/Jamfile b/test/Jamfile index 59607f2..5901b70 100755 --- a/test/Jamfile +++ b/test/Jamfile @@ -1,3 +1,7 @@ +# Copyright David Abrahams, Daniel Wallin 2006. 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 Parameter Library test Jamfile subproject libs/parameter/test ; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8a6be9a..f5ebfd9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,3 +1,7 @@ +# Copyright David Abrahams, Daniel Wallin 2006. 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 Parameter Library test Jamfile project boost/parameter diff --git a/test/python.py b/test/python.py index 8bd2a56..cf4d8de 100644 --- a/test/python.py +++ b/test/python.py @@ -1,3 +1,7 @@ +# Copyright Daniel Wallin 2006. 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) + ''' >>> from python_parameter import X >>> x = X(y = 'baz') From c29a75c9dfe37b0db40fd58b52587bcd377925a6 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 13 Sep 2006 00:40:00 +0000 Subject: [PATCH 18/58] merged from trunk [SVN r35083] --- test/mpl.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/test/mpl.cpp b/test/mpl.cpp index 10def06..b611543 100755 --- a/test/mpl.cpp +++ b/test/mpl.cpp @@ -9,9 +9,7 @@ #include #include -# include -# include -# include +# include namespace test { @@ -23,13 +21,7 @@ namespace test template void operator()(T*) { -#if 1 // mpl::set is too unreliable in this release. - typedef typename mpl::find::type pos; - typedef typename mpl::end::type not_found; - BOOST_MPL_ASSERT_NOT((boost::is_same)); -#else - BOOST_MPL_ASSERT((mpl::has_key)); -#endif + BOOST_MPL_ASSERT((mpl::contains)); } }; @@ -42,7 +34,7 @@ namespace test , == , mpl::size::value ); - + mpl::for_each >(assert_in_set()); } From c5168be5d76e15b057dd72b31e006be2fcc53a62 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 13 Sep 2006 03:15:16 +0000 Subject: [PATCH 19/58] Parameter library Workarounds for Borland and MSVC Parameter library explicit markup for expected failures value_init.hpp: Borland workarounds Use angle-includes consistently [SVN r35085] --- include/boost/parameter/aux_/maybe.hpp | 28 +++++++++---------- .../boost/parameter/aux_/tagged_argument.hpp | 2 +- test/maybe.cpp | 1 + 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/include/boost/parameter/aux_/maybe.hpp b/include/boost/parameter/aux_/maybe.hpp index ddb06e0..62c9bf8 100755 --- a/include/boost/parameter/aux_/maybe.hpp +++ b/include/boost/parameter/aux_/maybe.hpp @@ -12,6 +12,7 @@ # include # include # include +# include namespace boost { namespace parameter { namespace aux { @@ -20,18 +21,18 @@ struct maybe_base {}; template struct maybe : maybe_base { - typedef typename mpl::if_< - is_reference - , T - , typename add_reference< + typedef typename add_reference< # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) T const # else typename add_const::type # endif - >::type >::type reference; + typedef typename remove_cv< + BOOST_DEDUCED_TYPENAME remove_reference::type + >::type non_cv_value; + explicit maybe(T value) : value(value) , constructed(false) @@ -44,7 +45,7 @@ struct maybe : maybe_base ~maybe() { if (constructed) - destroy((void(*)(reference))0); + this->destroy(); } reference construct(reference value) const @@ -52,24 +53,23 @@ struct maybe : maybe_base return value; } - template - reference construct(U const& value, void(*)(V&)) const + template + reference construct2(U const& value) const { - new (m_storage.bytes) V(value); + new (m_storage.bytes) non_cv_value(value); constructed = true; - return *(V*)m_storage.bytes; + return *(non_cv_value*)m_storage.bytes; } template reference construct(U const& value) const { - return construct(value, (void(*)(reference))0); + return this->construct2(value); } - template - void destroy(void(*)(U&)) + void destroy() { - ((U*)m_storage.bytes)->~U(); + ((non_cv_value*)m_storage.bytes)->~non_cv_value(); } typedef reference(maybe::*safe_bool)() const; diff --git a/include/boost/parameter/aux_/tagged_argument.hpp b/include/boost/parameter/aux_/tagged_argument.hpp index d09e8ab..37d5c4a 100755 --- a/include/boost/parameter/aux_/tagged_argument.hpp +++ b/include/boost/parameter/aux_/tagged_argument.hpp @@ -74,7 +74,7 @@ struct tagged_argument : tagged_argument_base return value; } -# ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +# if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) template Default& get_with_default(default_ const& x, int) const { diff --git a/test/maybe.cpp b/test/maybe.cpp index b9fbc4d..8046300 100755 --- a/test/maybe.cpp +++ b/test/maybe.cpp @@ -30,5 +30,6 @@ int main() assert(f(unused = 0) == 1); assert(f((kw = maybe(), unused = 0)) == 1); assert(f((kw = maybe(2), unused = 0)) == 2); + return 0; } From d42b860b8d5c03f72d925c84bf34691e4fc38310 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 16 Sep 2006 18:15:08 +0000 Subject: [PATCH 20/58] Sun workarounds [SVN r35137] --- test/preprocessor.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/preprocessor.cpp b/test/preprocessor.cpp index 3ca752c..1495a8b 100755 --- a/test/preprocessor.cpp +++ b/test/preprocessor.cpp @@ -250,6 +250,27 @@ sfinae(A0 const& a0) } #endif +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) + +// Sun has problems with this syntax: +// +// template1< r* ( template2 ) > +// +// Workaround: factor template2 into a separate typedef +typedef boost::is_convertible predicate; + +BOOST_PARAMETER_FUNCTION( + (int), sfinae1, tag, + (required + (name, *(predicate)) + ) +) +{ + return 1; +} + +#else + BOOST_PARAMETER_FUNCTION( (int), sfinae1, tag, (required @@ -259,6 +280,7 @@ BOOST_PARAMETER_FUNCTION( { return 1; } +#endif #ifndef BOOST_NO_SFINAE // On compilers that actually support SFINAE, add another overload @@ -386,7 +408,13 @@ int main() assert(sfinae("foo") == 1); assert(sfinae(1) == 0); +# if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) + // Sun actually eliminates the desired overload for some reason. + // Disabling this part of the test because SFINAE abilities are + // not the point of this test. assert(sfinae1("foo") == 1); +# endif + assert(sfinae1(1) == 0); #endif return 0; From 0417a366932c06bd32e73dd4122a7da00a7fce23 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 18 Sep 2006 18:11:49 +0000 Subject: [PATCH 21/58] merged from HEAD [SVN r35163] --- include/boost/parameter/preprocessor.hpp | 50 ++++++++++++++++++------ 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/include/boost/parameter/preprocessor.hpp b/include/boost/parameter/preprocessor.hpp index 1a594d9..a67bc16 100755 --- a/include/boost/parameter/preprocessor.hpp +++ b/include/boost/parameter/preprocessor.hpp @@ -10,6 +10,7 @@ # include # include +# include # include # include @@ -47,6 +48,19 @@ struct unwrap_predicate typedef mpl::always type; }; +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) + +typedef void* voidstar; + +// A matching predicate is explicitly specified +template +struct unwrap_predicate +{ + typedef Predicate type; +}; + +#else + // A matching predicate is explicitly specified template struct unwrap_predicate @@ -54,6 +68,9 @@ struct unwrap_predicate typedef Predicate type; }; +#endif + + // A type to which the argument is supposed to be convertible is // specified template @@ -534,6 +551,16 @@ T const& as_lvalue(T const& value, int) >::get() | boost::parameter::aux::as_lvalue(BOOST_PARAMETER_FN_ARG_DEFAULT(arg), 0L) # endif +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_GET_ARG(arg, tag_ns) \ + BOOST_PARAMETER_FUNCTION_CAST( \ + args[ \ + BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT( \ + arg, tag_ns \ + ) \ + ] \ + , BOOST_PARAMETER_FN_ARG_PRED(arg) \ + ) + # define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_BODY(name, n, split_args, tag_namespace) \ { \ return BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ @@ -544,15 +571,13 @@ T const& as_lvalue(T const& value, int) , n \ , split_args \ ) \ - , args[ \ - BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT( \ - BOOST_PP_SEQ_ELEM( \ - BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(4,2,split_args), n) \ - , BOOST_PP_TUPLE_ELEM(4,3,split_args) \ - ) \ - , tag_namespace \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_GET_ARG( \ + BOOST_PP_SEQ_ELEM( \ + BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(4,2,split_args), n) \ + , BOOST_PP_TUPLE_ELEM(4,3,split_args) \ ) \ - ] \ + , tag_namespace \ + ) \ ); \ } @@ -598,9 +623,12 @@ T const& as_lvalue(T const& value, int) ) # define BOOST_PARAMETER_FUNCTION_DEFAULT_GET_ARG(r, tag_ns, arg) \ - , args[ \ - boost::parameter::keyword::get() \ - ] + , BOOST_PARAMETER_FUNCTION_CAST( \ + args[ \ + boost::parameter::keyword::get() \ + ] \ + , BOOST_PARAMETER_FN_ARG_PRED(arg) \ + ) // Generates the function template that recives a ArgumentPack, and then // goes on to call the layers of overloads generated by From 22a1f905e9465e59a8878e640f09f91e40e3f1a2 Mon Sep 17 00:00:00 2001 From: nobody Date: Mon, 18 Sep 2006 19:56:20 +0000 Subject: [PATCH 22/58] This commit was manufactured by cvs2svn to create branch 'RC_1_34_0'. [SVN r35170] --- include/boost/parameter/aux_/cast.hpp | 93 +++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100755 include/boost/parameter/aux_/cast.hpp diff --git a/include/boost/parameter/aux_/cast.hpp b/include/boost/parameter/aux_/cast.hpp new file mode 100755 index 0000000..863ec75 --- /dev/null +++ b/include/boost/parameter/aux_/cast.hpp @@ -0,0 +1,93 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to 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) + +#ifndef BOOST_PARAMETER_CAST_060902_HPP +# define BOOST_PARAMETER_CAST_060902_HPP + +# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + && !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# include +# include +# endif + +namespace boost { namespace parameter { namespace aux { + +# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +# define BOOST_PARAMETER_FUNCTION_CAST(value, predicate) value + +# else + +// Handles possible implicit casts. Used by preprocessor.hpp to +// normalize user input. +// +// cast::execute() is identity +// cast::execute() is identity +// cast::execute() casts to X +// +// preprocessor.hpp uses this like this: +// +// #define X(value, predicate) +// cast::execute(value) +// +// X(something, *) +// X(something, *(predicate)) +// X(something, (int)) + +template +struct cast; + +template <> +struct cast +{ + template + static U& execute(U& value) + { + return value; + } +}; + +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) + +typedef void* voidstar; + +template +struct cast + : cast +{ +}; + +#else + +template +struct cast + : cast +{ +}; + +#endif + +template +struct cast +{ + typedef typename boost::add_reference< + typename boost::add_const::type + >::type reference; + + static reference execute(reference value) + { + return value; + } +}; + +# define BOOST_PARAMETER_FUNCTION_CAST(value, predicate) \ + boost::parameter::aux::cast::execute(value) + +# endif + +}}} // namespace boost::parameter::aux + +#endif // BOOST_PARAMETER_CAST_060902_HPP + From c7258e9c9e686e5a17df07c35ea71b6acd2b4156 Mon Sep 17 00:00:00 2001 From: nobody Date: Mon, 18 Sep 2006 20:05:46 +0000 Subject: [PATCH 23/58] This commit was manufactured by cvs2svn to create branch 'RC_1_34_0'. [SVN r35173] --- test/deduced.cpp | 180 ++++++++++++++++++++++++++++++++++ test/preprocessor_deduced.cpp | 110 +++++++++++++++++++++ test/python_test.cpp | 159 ++++++++++++++++++++++++++++++ test/python_test.py | 41 ++++++++ 4 files changed, 490 insertions(+) create mode 100755 test/deduced.cpp create mode 100755 test/preprocessor_deduced.cpp create mode 100755 test/python_test.cpp create mode 100644 test/python_test.py diff --git a/test/deduced.cpp b/test/deduced.cpp new file mode 100755 index 0000000..2d744a2 --- /dev/null +++ b/test/deduced.cpp @@ -0,0 +1,180 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to 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) + +#include +#include +#include +#include +#include "basics.hpp" + +namespace parameter = boost::parameter; +namespace mpl = boost::mpl; + +struct not_present_tag {}; +not_present_tag not_present; + +BOOST_PARAMETER_NAME(x) +BOOST_PARAMETER_NAME(y) +BOOST_PARAMETER_NAME(z) + +template +struct assert_expected +{ + assert_expected(E const& e, ArgPack const& args) + : expected(e) + , args(args) + {} + + template + bool check_not_present(T const&) const + { + BOOST_MPL_ASSERT((boost::is_same)); + return true; + } + + template + bool check(K const& k, not_present_tag const&, long) const + { + return check_not_present(args[k | not_present]); + } + + template + bool check(K const& k, Expected const& expected, int) const + { + return test::equal(args[k], expected); + } + + template + void operator()(K) const + { + parameter::keyword const& k = parameter::keyword::get(); + assert(check(k, expected[k], 0L)); + } + + E const& expected; + ArgPack const& args; +}; + +template +void check0(E const& e, ArgPack const& args) +{ + mpl::for_each(assert_expected(e, args)); +} + +template +void check(E const& e, A0 const& a0) +{ + check0(e, P()(a0)); +} + +template +void check(E const& e, A0 const& a0, A1 const& a1) +{ + check0(e, P()(a0,a1)); +} + +template +void check(E const& e, A0 const& a0, A1 const& a1, A2 const& a2) +{ + check0(e, P()(a0,a1,a2)); +} + +int main() +{ + using namespace parameter; + + check< + parameters< + tag::x + , tag::y + > + >( + (_x = 0, _y = 1) + , 0 + , 1 + ); + + check< + parameters< + tag::x + , required, boost::is_convertible > + , optional, boost::is_convertible > + > + >( + (_x = 0, _y = not_present, _z = "foo") + , _x = 0 + , "foo" + ); + + check< + parameters< + tag::x + , required, boost::is_convertible > + , optional, boost::is_convertible > + > + >( + (_x = 0, _y = 1, _z = "foo") + , 0 + , "foo" + , 1 + ); + + check< + parameters< + tag::x + , required, boost::is_convertible > + , optional, boost::is_convertible > + > + >( + (_x = 0, _y = 1, _z = "foo") + , 0 + , 1 + , "foo" + ); + + check< + parameters< + tag::x + , required, boost::is_convertible > + , optional, boost::is_convertible > + > + >( + (_x = 0, _y = 1, _z = "foo") + , 0 + , _y = 1 + , "foo" + ); + + check< + parameters< + tag::x + , required, boost::is_convertible > + , optional, boost::is_convertible > + > + >( + (_x = 0, _y = 1, _z = "foo") + , _z = "foo" + , _x = 0 + , 1 + ); + + // Fails becasue of parameters.hpp:428 +/* + check< + parameters< + tag::x + , required, boost::is_convertible > + , optional, boost::is_convertible > + > + >( + (_x = 0, _y = 1, _z = "foo") + , _x = 0 + , (long*)0 + , 1 + ); +*/ + + return 0; +}; + diff --git a/test/preprocessor_deduced.cpp b/test/preprocessor_deduced.cpp new file mode 100755 index 0000000..04ca1fb --- /dev/null +++ b/test/preprocessor_deduced.cpp @@ -0,0 +1,110 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to 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) + +#include +#include +#include +#include +#include +#include "basics.hpp" + +namespace test { + +namespace mpl = boost::mpl; + +using mpl::_; +using boost::is_convertible; + +BOOST_PARAMETER_NAME(expected) +BOOST_PARAMETER_NAME(x) +BOOST_PARAMETER_NAME(y) +BOOST_PARAMETER_NAME(z) + +BOOST_PARAMETER_FUNCTION((int), f, tag, + (required + (expected, *) + ) + (deduced + (required + (x, *(is_convertible<_, int>)) + (y, *(is_convertible<_, std::string>)) + ) + ) +) +{ + assert(equal(x, boost::tuples::get<0>(expected))); + assert(equal(y, boost::tuples::get<1>(expected))); + return 1; +} + +struct X +{ + X(int x = -1) + : x(x) + {} + + bool operator==(X const& other) const + { + return x == other.x; + } + + int x; +}; + +BOOST_PARAMETER_FUNCTION((int), g, tag, + (required + (expected, *) + ) + (deduced + (required + (x, *(is_convertible<_, int>)) + (y, *(is_convertible<_, std::string>)) + ) + (optional + (z, *(is_convertible<_, X>), X()) + ) + ) +) +{ + assert(equal(x, boost::tuples::get<0>(expected))); + assert(equal(y, boost::tuples::get<1>(expected))); + assert(equal(z, boost::tuples::get<2>(expected))); + return 1; +} + +} // namespace test + +using boost::make_tuple; + +// make_tuple doesn't work with char arrays. +char const* str(char const* s) +{ + return s; +} + +int main() +{ + using namespace test; + + f(make_tuple(0, str("foo")), _x = 0, _y = "foo"); + f(make_tuple(0, str("foo")), _x = 0, _y = "foo"); + f(make_tuple(0, str("foo")), 0, "foo"); + f(make_tuple(0, str("foo")), "foo", 0); + f(make_tuple(0, str("foo")), _y = "foo", 0); + f(make_tuple(0, str("foo")), _x = 0, "foo"); + f(make_tuple(0, str("foo")), 0, _y = "foo"); + + g(make_tuple(0, str("foo"), X()), _x = 0, _y = "foo"); + g(make_tuple(0, str("foo"), X()), 0, "foo"); + g(make_tuple(0, str("foo"), X()), "foo", 0); + g(make_tuple(0, str("foo"), X()), _y = "foo", 0); + g(make_tuple(0, str("foo"), X()), _x = 0, "foo"); + g(make_tuple(0, str("foo"), X()), 0, _y = "foo"); + + g(make_tuple(0, str("foo"), X(1)), 0, _y = "foo", X(1)); + g(make_tuple(0, str("foo"), X(1)), X(1), 0, _y = "foo"); + + return 0; +} + diff --git a/test/python_test.cpp b/test/python_test.cpp new file mode 100755 index 0000000..a9612ae --- /dev/null +++ b/test/python_test.cpp @@ -0,0 +1,159 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to 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) + +#include +#include +#include +#include +#include + +namespace test { + +BOOST_PARAMETER_KEYWORD(tag, x) +BOOST_PARAMETER_KEYWORD(tag, y) +BOOST_PARAMETER_KEYWORD(tag, z) + +struct Xbase +{ + // We need the disable_if part for VC7.1/8.0. + template + Xbase( + Args const& args + , typename boost::disable_if< + boost::is_base_and_derived + >::type* = 0 + ) + : value(std::string(args[x | "foo"]) + args[y | "bar"]) + {} + + std::string value; +}; + +struct X : Xbase +{ + BOOST_PARAMETER_CONSTRUCTOR(X, (Xbase), tag, + (optional + (x, *) + (y, *) + ) + ) + + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION((int), f, tag, + (required + (x, *) + (y, *) + ) + (optional + (z, *) + ) + ) + { + return args[x] + args[y] + args[z | 0]; + } + + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION((std::string), g, tag, + (optional + (x, *) + (y, *) + ) + ) + { + return std::string(args[x | "foo"]) + args[y | "bar"]; + } + + BOOST_PARAMETER_MEMBER_FUNCTION((X&), h, tag, + (optional (x, *, "") (y, *, "")) + ) + { + return *this; + } + + template + X& operator()(A0 const& a0) + { + return *this; + } +}; + +} // namespace test + +struct f_fwd +{ + template + R operator()(boost::type, T& self, A0 const& a0, A1 const& a1, A2 const& a2) + { + return self.f(a0,a1,a2); + } +}; + +struct g_fwd +{ + template + R operator()(boost::type, T& self, A0 const& a0, A1 const& a1) + { + return self.g(a0,a1); + } +}; + +struct h_fwd +{ + template + R operator()(boost::type, T& self, A0 const& a0, A1 const& a1) + { + return self.h(a0,a1); + } +}; + +BOOST_PYTHON_MODULE(python_test_ext) +{ + namespace mpl = boost::mpl; + using namespace test; + using namespace boost::python; + + class_("X") + .def( + boost::parameter::python::init< + mpl::vector< + tag::x*(std::string), tag::y*(std::string) + > + >() + ) + .def( + "f" + , boost::parameter::python::function< + f_fwd + , mpl::vector< + int, tag::x(int), tag::y(int), tag::z*(int) + > + >() + ) + .def( + "g" + , boost::parameter::python::function< + g_fwd + , mpl::vector< + std::string, tag::x*(std::string), tag::y*(std::string) + > + >() + ) + .def( + "h" + , boost::parameter::python::function< + h_fwd + , mpl::vector< + X&, tag::x*(std::string), tag::y*(std::string) + > + >() + , return_arg<>() + ) + .def( + boost::parameter::python::call< + mpl::vector< + X&, tag::x(int) + > + >() [ return_arg<>() ] + ) + .def_readonly("value", &X::value); +} + diff --git a/test/python_test.py b/test/python_test.py new file mode 100644 index 0000000..ce3b81c --- /dev/null +++ b/test/python_test.py @@ -0,0 +1,41 @@ +# Copyright Daniel Wallin 2006. 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) + +''' +>>> from python_test_ext import X +>>> x = X(y = 'baz') +>>> x.value +'foobaz' +>>> x.f(1,2) +3 +>>> x.f(1,2,3) +6 +>>> x.f(1,2, z = 3) +6 +>>> x.f(z = 3, y = 2, x = 1) +6 +>>> x.g() +'foobar' +>>> x.g(y = "baz") +'foobaz' +>>> x.g(x = "baz") +'bazbar' +>>> x.g(y = "foo", x = "bar") +'barfoo' +>>> y = x.h(x = "bar", y = "foo") +>>> assert x == y +>>> y = x(0) +>>> assert x == y +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, python_test + return doctest.testmod(python_test) + +if __name__ == '__main__': + import sys + sys.exit(run()[0]) From 5231f04b27fa14c38a3bd8a2de46988625fa6807 Mon Sep 17 00:00:00 2001 From: Daniel Wallin Date: Mon, 18 Sep 2006 20:42:44 +0000 Subject: [PATCH 24/58] Merged changes from head to RC_1_34_0. [SVN r35177] --- doc/Jamfile.v2 | 2 +- doc/html/reference.html | 373 ++++++---- doc/reference.rst | 124 +++- include/boost/parameter/aux_/maybe.hpp | 7 +- include/boost/parameter/aux_/overloads.hpp | 21 +- .../parameter/aux_/preprocessor/flatten.hpp | 42 +- include/boost/parameter/binding.hpp | 11 +- include/boost/parameter/name.hpp | 18 +- include/boost/parameter/parameters.hpp | 659 ++++++++++++------ include/boost/parameter/preprocessor.hpp | 173 ++++- include/boost/parameter/python.hpp | 1 + test/Jamfile | 11 +- test/Jamfile.v2 | 6 + test/basics.cpp | 5 +- test/basics.hpp | 8 +- test/ntp.cpp | 9 +- test/preprocessor.cpp | 49 +- 17 files changed, 1104 insertions(+), 415 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index ae0636a..30439ef 100755 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -16,7 +16,7 @@ for local b in $(bases) html $(b) : $(b).rst : # - "-gdt --traceback --trim-footnote-reference-space --footnote-references=superscript "$(stylesheet) + "-gdt --link-stylesheet --traceback --trim-footnote-reference-space --footnote-references=superscript "$(stylesheet) ; } diff --git a/doc/html/reference.html b/doc/html/reference.html index 0b9aba2..610e921 100755 --- a/doc/html/reference.html +++ b/doc/html/reference.html @@ -3,97 +3,103 @@ - + The Boost Parameter Library Reference Documentation + + + +

The Boost Parameter Library Reference Documentation

-

Boost

- --+
++ - - - - - - - - - + + + + + + + + + - +or copy at http://www.boost.org/LICENSE_1_0.txt)
Authors:David Abrahams, Daniel Wallin
Contact:dave@boost-consulting.com, dalwan01@student.umu.se
organization:Boost Consulting
date:$Date: 2005/07/17 19:53:01 $
copyright:Copyright David Abrahams, Daniel Wallin +
Authors:David Abrahams +
Daniel Wallin
Contact:dave@boost-consulting.com, dalwan01@student.umu.se
Organization:Boost Consulting
Date:2005-07-17
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


-
-

Contents

+
-
-

1   Preliminaries

+
+

1   Preliminaries

This section covers some basic information you'll need to know in order to understand this reference

-
-

1.1   Namespaces

+
+

1.1   Namespaces

In this document, all unqualified identifiers should be assumed to be defined in namespace boost::parameter unless otherwise specified.

-
-

1.2   Exceptions

+
+

1.2   Exceptions

No operation described in this document throws an exception unless otherwise specified.

-
-

1.3   Thread Safety

+
+

1.3   Thread Safety

All components of this library can be used safely from multiple threads without synchronization.1

-
-

1.4   Typography

+
+

1.4   Typography

Names written in sans serif type represent concepts.

In code blocks, italic type represents unspecified text that satisfies the requirements given in the detailed description that @@ -105,9 +111,9 @@ argument in the result.


-
-

2   Terminology

-
+
+

2   Terminology

+
keyword
The name of a function parameter.
@@ -140,12 +146,12 @@ reference whose value is
-
tagged default
+
tagged default
A tagged reference whose value represents the value of a default argument.
-
tagged lazy default
+
tagged lazy default
A tagged reference whose value, when invoked with no arguments, computes a default argument value.
@@ -164,16 +170,16 @@ models ArgumentP

-
-

3   Concepts

+
+

3   Concepts

This section describes the generic type concepts used by the Parameter library.

-
-

3.1   ArgumentPack

+
+

3.1   ArgumentPack

An ArgumentPack is a collection of tagged references to the actual arguments passed to a function. Every ArgumentPack is also a valid MPL Forward Sequence consisting of the keyword tag types in its tagged references.

-
-

Requirements

+
+

Requirements

In the table below,

  • A is a model of ArgumentPack
  • @@ -194,10 +200,10 @@ will be propagated to the caller.

    -Expression -Type -Requirements -Semantics/Notes +Expression +Type +Requirements +Semantics/Notes @@ -236,14 +242,14 @@ all the elements of both x
-
-

3.2   ParameterSpec

+
+

3.2   ParameterSpec

A ParameterSpec describes the type requirements for arguments corresponding to a given keyword and indicates whether the argument is optional or required. The table below details the allowed forms and describes their condition for satisfaction by an actual argument type. In each row,

-
    +
    • K is the ParameterSpec's keyword tag type
    • A is an intended argument type associated with K, if any
    • F is a unary MPL lambda expression
    • @@ -256,9 +262,9 @@ argument type. In each row,

      -Type -A required -Condition A must satisfy +Type +A required +Condition A must satisfy @@ -283,10 +289,10 @@ arguments that will be matched by -
      -

      4   Class Templates

      -
      -

      4.1   keyword

      +
      +

      4   Class Templates

      + -
      -

      4.2   parameters

      +
      +

      4.2   parameters

      Provides an interface for assembling the actual arguments to a forwarding function into an ArgumentPack, in which any positional arguments will be tagged according to the @@ -411,8 +417,10 @@ struct parameters ArgumentPack operator()(A0 const& a0) const; template <class A0, class A1> - ArgumentPack operator()(A0 const& a0, A1 const& a1) const; - + ArgumentPack operator()(A0 const& a0, A1 const& a1) const; . + . + . +  template <class A0, class A1, …class Aβ> ArgumentPack operator()(A0 const& a0, A1 const& a1, …Aβ const& aβ) const; }; @@ -435,11 +443,11 @@ follows, for any argument type A<


      if Ai is a result type of keyword<T>::operator=
      -
      then
      +
      then
      Ki is T
      -
      else
      +
      else
      Ki is Pi's keyword tag type.
      @@ -447,7 +455,7 @@ follows, for any argument type A<
      -
      +
      match

      A Metafunction used to remove a forwarding function from overload resolution.

      @@ -478,11 +486,13 @@ every j in 0…β, either:

      -
      +
      operator()
      -template <class A0> ArgumentPack operator()(A0 const& a0) const;
      -   
      +template <class A0> ArgumentPack operator()(A0 const& a0) const;   .
      +  .
      +  .
      + 
       template <class A0, …class Aβ> ArgumentPack operator()(A0 const& a0, …Aβ const& aβ) const;
       
      @@ -501,8 +511,8 @@ template <class A0, …class Aβ> -

      4.3   optional, required

      +
      +

      4.3   optional, required

      These templates describe the requirements on a function parameter.

      @@ -533,12 +543,12 @@ struct required;
      -
      -

      5   Metafunctions

      +
      +

      5   Metafunctions

      A Metafunction is conceptually a function that operates on, and returns, C++ types.

      -
      -

      5.1   binding

      +
      +

      5.1   binding

      Returns the result type of indexing an argument pack with a keyword tag type or with a tagged default.

      @@ -568,8 +578,8 @@ having keyword tag type
      -
      -

      5.2   lazy_binding

      +
      +

      5.2   lazy_binding

      Returns the result type of indexing an argument pack with a tagged lazy default.

      @@ -600,12 +610,136 @@ having keyword tag type
      -
      -

      6   Code Generation Macros

      +
      +

      6   Code Generation Macros

      Macros in this section can be used to ease the writing of code using the Parameter libray by eliminating repetitive boilerplate.

      -
      +++ + + + +
      Defined in:boost/parameter/preprocessor.hpp
      + +++ + + + + + + +
      Requires:

      result is the parenthesized return type of the function. +name is the base name of the function, this is the name of the +generated forwarding functions. tag_namespace is the namespace in +which the keywords used by the function resides. arguments is +a list of argument specifiers, as defined below.

      +
      Argument specifiers syntax:
       
      +argument-specifiers ::= specifier-group {specifier-group}
      +
      +specifier-group ::= ( '(' 'optional' optional-specifier {optional-specifier} ')' ) |
      +                    ( '(' 'required' required-specifier {required-specifier} ')' )
      +
      +optional-specifier ::= '(' name ',' restriction ',' default-value ')'
      +required-specifier ::= '(' name ',' restriction ')'
      +
      +restriction ::= ('*' '(' lambda-expression ')' ) |
      +                ( '(' typename ')' ) |
      +                '*'
      +
      +

      name is any valid C++ identifier. default-value is any valid +C++ expression. typename is the name of a type. +lambda-expression is an MPL lambda expression.

      +
      + +++ + + + + +
      Generated names in enclosing scope:
       
        +
      • boost_param_result_ ## __LINE__ ## name
      • +
      • boost_param_params_ ## __LINE__ ## name
      • +
      • boost_param_parameters_ ## __LINE__ ## name
      • +
      • boost_param_impl ## name
      • +
      • boost_param_default_ ## __LINE__ ## name
      • +
      +
      +
      +
      Approximate expansion:
      +

      Where:

      +
        +
      • n denotes the minimum arity, as determined from arguments.
      • +
      • m denotes the maximum arity, as determined from arguments.
      • +
      +
      +template <class T>
      +struct boost_param_result_ ## __LINE__ ## name
      +{
      +    typedef result type;
      +};
      +
      +struct boost_param_params_ ## __LINE__ ## name
      +  : boost::parameter::parameters<
      +        list of parameter specifications, based on arguments
      +    >
      +{};
      +
      +typedef boost_param_params_ ## __LINE__ ## name
      +  boost_param_parameters_ ## __LINE__ ## name;
      +
      +template <class A0, …, class An>
      +result type name(
      +    A0 cv& a0, …, An cv& an
      +  , typename boost_param_parameters_ ## __LINE__ ## name::match<
      +      A0 cv, …, An cv
      +    >::type = boost_param_parameters_ ## __LINE__ ## name()
      +)
      +{
      +    … forward to implementation …
      +}
      +
      +  .
      +  .
      +  .
      + 
      +
      +template <class A0, …, class Am>
      +result type name(
      +    A0 cv& a0, …, Am cv& am
      +  , typename boost_param_parameters_ ## __LINE__ ## name::match<
      +      A0 cv, …, Am cv
      +    >::type = boost_param_parameters_ ## __LINE__ ## name()
      +)
      +{
      +    … forward to implementation …
      +}
      +
      +template <
      +    class ResultType
      +  , class argument name0 ## _type
      +    …
      +  , class argument namem ## _type
      +>
      +ResultType boost_param_default_ ## __LINE__ ## name(
      +    (ResultType(*)())
      +  , argument name0 ## _type& argument name0
      +    …
      +  , argument namem ## _type& argument namem
      +)
      +
      +
      +
      +
      +
      +

      6.2   BOOST_PARAMETER_FUN(r,n,l,h,p)

      Generates a sequence of forwarding function templates named n, with arities ranging from l to h , returning r, and using p to control overload resolution and assign tags to @@ -645,8 +779,10 @@ r name( , typename p::match<A1,A2,…Al,A##BOOST_PP_INC(l)>::type p = p()) { return name_with_named_params(p(x1,x2,…xl,x##BOOST_PP_INC(l))); -} - +} . + . + . +  template <class A1, class A2, …class Ah> r name( A1 const& a1, A2 const& a2, …Ah const& xh @@ -658,8 +794,8 @@ r name(

      -
      -

      6.2   BOOST_PARAMETER_KEYWORD(n,k)

      +
      +

      6.3   BOOST_PARAMETER_KEYWORD(n,k)

      Generates the declaration of a keyword tag type named k in namespace n, and a corresponding keyword object definition in the enclosing namespace.

      @@ -675,7 +811,7 @@ the enclosing namespace.

      Generates
       namespace n { struct k; }
      -namespace { 
      +namespace {
         boost::parameter::keyword<tag-namespace::k>& k
         = boost::parameter::keyword<tag-namespace::k>::get();
       }
      @@ -683,8 +819,8 @@ namespace {
       
      -
      -

      6.3   BOOST_PARAMETER_MATCH(p,a,x)

      +
      +

      6.4   BOOST_PARAMETER_MATCH(p,a,x)

      Generates a defaulted parameter declaration for a forwarding function.

      @@ -699,7 +835,7 @@ function.

      -
      Requires:

      a is a Boost.Preprocessor sequence +

      Requires:

      a is a Boost.Preprocessor sequence of the form

       (A0)(A1)…(An)
      @@ -717,10 +853,10 @@ typename p::match<A0,A1…
       
       
       
      -
      -

      7   Configuration Macros

      -
      -

      7.1   BOOST_PARAMETER_MAX_ARITY

      +
      +

      7   Configuration Macros

      +
      +

      7.1   BOOST_PARAMETER_MAX_ARITY

      Determines the maximum number of arguments supported by the library. Will only be #defined by the library if it is not already #defined.

      @@ -742,8 +878,8 @@ already #defined.

      -
      -

      8   Tutorial

      +
      +

      8   Tutorial

      Follow this link to the Boost.Parameter tutorial documentation.


      @@ -768,10 +904,11 @@ where it could make a difference.
      - diff --git a/doc/reference.rst b/doc/reference.rst index b3ed4e8..8c43f67 100755 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -2,13 +2,6 @@ The Boost Parameter Library Reference Documentation +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -|(logo)|__ - -.. |(logo)| image:: ../../../../boost.png - :alt: Boost - -__ ../../../../index.htm - :Authors: David Abrahams, Daniel Wallin :Contact: dave@boost-consulting.com, dalwan01@student.umu.se :organization: `Boost Consulting`_ @@ -19,6 +12,13 @@ __ ../../../../index.htm Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +|(logo)|__ + +.. |(logo)| image:: ../../../../boost.png + :alt: Boost + +__ ../../../../index.htm + .. _`Boost Consulting`: http://www.boost-consulting.com @@ -554,6 +554,113 @@ Code Generation Macros Macros in this section can be used to ease the writing of code using the Parameter libray by eliminating repetitive boilerplate. +``BOOST_PARAMETER_FUNCTION(result,name,tag_namespace,arguments)`` +----------------------------------------------------------------- + +:Defined in: `boost/parameter/preprocessor.hpp`__ + +__ ../../../../boost/parameter/preprocessor.hpp + +:Requires: ``result`` is the parenthesized return type of the function. + ``name`` is the base name of the function, this is the name of the + generated forwarding functions. ``tag_namespace`` is the namespace in + which the keywords used by the function resides. ``arguments`` is + a list of *argument specifiers*, as defined below. + + +:Argument specifiers syntax: + .. parsed-literal:: + + argument-specifiers ::= specifier-group {specifier-group} + + specifier-group ::= ( '(' 'optional' optional-specifier {optional-specifier} ')' ) | + ( '(' 'required' required-specifier {required-specifier} ')' ) + + optional-specifier ::= '(' name ',' restriction ',' default-value ')' + required-specifier ::= '(' name ',' restriction ')' + + restriction ::= ('*' '(' lambda-expression ')' ) | + ( '(' typename ')' ) | + '*' + + ``name`` is any valid C++ identifier. ``default-value`` is any valid + C++ expression. ``typename`` is the name of a type. + ``lambda-expression`` is an `MPL lambda expression`_. + +.. _`MPL lambda expression`: ../../../mpl/doc/refmanual/lambda-expression.html + +:Generated names in enclosing scope: + * ``boost_param_result_ ## __LINE__ ## name`` + * ``boost_param_params_ ## __LINE__ ## name`` + * ``boost_param_parameters_ ## __LINE__ ## name`` + * ``boost_param_impl ## name`` + * ``boost_param_default_ ## __LINE__ ## name`` + + +Approximate expansion: + **Where**: + + * ``n`` denotes the *minimum* arity, as determined from ``arguments``. + * ``m`` denotes the *maximum* arity, as determined from ``arguments``. + + .. parsed-literal:: + + template + struct boost_param_result\_ ## __LINE__ ## **name** + { + typedef **result** type; + }; + + struct boost_param_params\_ ## __LINE__ ## **name** + : boost::parameter::parameters< + *list of parameter specifications, based on arguments* + > + {}; + + typedef boost_param_params\_ ## __LINE__ ## **name** + boost_param_parameters\_ ## __LINE__ ## **name**; + + template + *result type* **name**\ ( + A0 *cv*\ & a0, …, A\ **n** *cv*\ & a\ **n** + , typename boost_param_parameters\_ ## __LINE__ ## **name**::match< + A0 *cv*, …, A\ **n** *cv* + >::type = boost_param_parameters\_ ## __LINE__ ## **name**\ () + ) + { + *… forward to implementation …* + } + + :vellipsis:`\ + . + . + . +  ` + + template + *result type* **name**\ ( + A0 *cv*\ & a0, …, A\ **m** *cv*\ & a\ **m** + , typename boost_param_parameters\_ ## __LINE__ ## **name**::match< + A0 *cv*, …, A\ **m** *cv* + >::type = boost_param_parameters\_ ## __LINE__ ## **name**\ () + ) + { + *… forward to implementation …* + } + + template < + class ResultType + , class *argument name*\ **0** ## _type + … + , class *argument name*\ **m** ## _type + > + ResultType boost_param_default\_ ## __LINE__ ## **name**\ ( + (ResultType(*)()) + , *argument name*\ **0** ## _type& *argument name*\ **0** + … + , *argument name*\ **m** ## _type& *argument name*\ **m** + ) + ``BOOST_PARAMETER_FUN(r,n,l,h,p)`` ---------------------------------- @@ -691,4 +798,5 @@ __ index.html#tutorial .. _result_of: ../../../utility/utility.htm#result_of .. |BOOST_NO_RESULT_OF| replace:: ``BOOST_NO_RESULT_OF`` -.. _BOOST_NO_RESULT_OF: ../../../utility/utility.htm#BOOST_NO_RESULT_OF \ No newline at end of file +.. _BOOST_NO_RESULT_OF: ../../../utility/utility.htm#BOOST_NO_RESULT_OF + diff --git a/include/boost/parameter/aux_/maybe.hpp b/include/boost/parameter/aux_/maybe.hpp index 62c9bf8..9c99e81 100755 --- a/include/boost/parameter/aux_/maybe.hpp +++ b/include/boost/parameter/aux_/maybe.hpp @@ -9,7 +9,6 @@ # include # include # include -# include # include # include # include @@ -23,12 +22,12 @@ struct maybe : maybe_base { typedef typename add_reference< # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) - T const + T const # else - typename add_const::type + typename add_const::type # endif >::type reference; - + typedef typename remove_cv< BOOST_DEDUCED_TYPENAME remove_reference::type >::type non_cv_value; diff --git a/include/boost/parameter/aux_/overloads.hpp b/include/boost/parameter/aux_/overloads.hpp index 406682d..9d9b1f5 100755 --- a/include/boost/parameter/aux_/overloads.hpp +++ b/include/boost/parameter/aux_/overloads.hpp @@ -44,17 +44,22 @@ #define N BOOST_PP_ITERATION() #define BOOST_PARAMETER_open_list(z, n, text) \ - aux::make_arg_list< \ - BOOST_PP_CAT(PS, n), BOOST_PP_CAT(A, n), aux::tag_keyword_arg + aux::item< \ + BOOST_PP_CAT(PS, n), BOOST_PP_CAT(A, n) #define BOOST_PARAMETER_close_list(z, n, text) > #define BOOST_PARAMETER_arg_list(n) \ - mpl::apply_wrap1< \ - BOOST_PP_ENUM(N, BOOST_PARAMETER_open_list, _) \ - , mpl::always \ - BOOST_PP_REPEAT(N, BOOST_PARAMETER_close_list, _) \ - , unnamed_list> + aux::make_arg_list< \ + BOOST_PP_ENUM(N, BOOST_PARAMETER_open_list, _) \ + , void_ \ + BOOST_PP_REPEAT(N, BOOST_PARAMETER_close_list, _) \ + , deduced_list \ + , aux::tag_keyword_arg \ + > + +#define BOOST_PARAMETER_arg_pack_init(z, n, limit) \ + BOOST_PP_CAT(a, BOOST_PP_SUB(limit,n)) template typename BOOST_PARAMETER_arg_list(N)::type @@ -63,7 +68,7 @@ operator()(BOOST_PP_ENUM_BINARY_PARAMS(N, A, & a)) const typedef typename BOOST_PARAMETER_arg_list(N)::type arg_tuple; return arg_tuple( - BOOST_PP_ENUM_PARAMS(N, a) + BOOST_PP_ENUM(N, BOOST_PARAMETER_arg_pack_init, BOOST_PP_DEC(N)) BOOST_PP_ENUM_TRAILING_PARAMS( BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, N) , aux::void_reference() BOOST_PP_INTERCEPT diff --git a/include/boost/parameter/aux_/preprocessor/flatten.hpp b/include/boost/parameter/aux_/preprocessor/flatten.hpp index 2bd7539..5d7615e 100755 --- a/include/boost/parameter/aux_/preprocessor/flatten.hpp +++ b/include/boost/parameter/aux_/preprocessor/flatten.hpp @@ -9,14 +9,16 @@ # include # include # include +# include +# include # include # include # include - # include # define BOOST_PARAMETER_FLATTEN_SPLIT_required required, # define BOOST_PARAMETER_FLATTEN_SPLIT_optional optional, +# define BOOST_PARAMETER_FLATTEN_SPLIT_deduced deduced, # define BOOST_PARAMETER_FLATTEN_SPLIT(sub) \ BOOST_PP_CAT(BOOST_PARAMETER_FLATTEN_SPLIT_, sub) @@ -48,16 +50,18 @@ ) \ )) -# define BOOST_PARAMETER_FLATTEN_SPEC_AUX(r, arity, max_arity, spec) \ +# define BOOST_PARAMETER_FLATTEN_SPEC_AUX(r, arity, max_arity, spec, transform) \ BOOST_PARAMETER_FOR_EACH_R( \ r \ , arity \ , BOOST_PARAMETER_FLATTEN_ARGS(spec) \ - , (arity, max_arity, BOOST_PARAMETER_FLATTEN_QUALIFIER(spec)) \ + , (arity, max_arity, transform(BOOST_PARAMETER_FLATTEN_QUALIFIER(spec))) \ , BOOST_PARAMETER_FLATTEN_SPEC0 \ ) -# define BOOST_PARAMETER_FLATTEN_SPEC(r, arities, spec) \ +# define BOOST_PARAMETER_FLATTEN_IDENTITY(x) x + +# define BOOST_PARAMETER_FLATTEN_SPEC_optional(r, arities, spec) \ BOOST_PARAMETER_FLATTEN_SPEC_AUX( \ r \ , BOOST_PP_CAT( \ @@ -65,8 +69,38 @@ )(arities) \ , BOOST_PP_TUPLE_ELEM(3,2,arities) \ , spec \ + , BOOST_PARAMETER_FLATTEN_IDENTITY \ ) +# define BOOST_PARAMETER_FLATTEN_SPEC_required(r, arities, spec) \ + BOOST_PARAMETER_FLATTEN_SPEC_optional(r, arities, spec) + +# define BOOST_PARAMETER_FLATTEN_SPEC_AS_DEDUCED(x) BOOST_PP_CAT(deduced_,x) + +# define BOOST_PARAMETER_FLATTEN_SPEC_deduced_M(r, arities, n, spec) \ + BOOST_PARAMETER_FLATTEN_SPEC_AUX( \ + r \ + , BOOST_PP_CAT( \ + BOOST_PARAMETER_FLATTEN_ARITY_, BOOST_PARAMETER_FLATTEN_QUALIFIER(spec) \ + )(arities) \ + , BOOST_PP_TUPLE_ELEM(3,2,arities) \ + , spec \ + , BOOST_PARAMETER_FLATTEN_SPEC_AS_DEDUCED \ + ) + +# define BOOST_PARAMETER_FLATTEN_SPEC_deduced(r, arities, spec) \ + BOOST_PP_SEQ_FOR_EACH_I_R( \ + r \ + , BOOST_PARAMETER_FLATTEN_SPEC_deduced_M \ + , arities \ + , BOOST_PARAMETER_FLATTEN_ARGS(spec) \ + ) + +# define BOOST_PARAMETER_FLATTEN_SPEC(r, arities, spec) \ + BOOST_PP_CAT( \ + BOOST_PARAMETER_FLATTEN_SPEC_, BOOST_PARAMETER_FLATTEN_QUALIFIER(spec) \ + )(r, arities, spec) + # define BOOST_PARAMETER_FLATTEN(optional_arity, required_arity, wanted_arity, specs) \ BOOST_PP_SEQ_FOR_EACH( \ BOOST_PARAMETER_FLATTEN_SPEC \ diff --git a/include/boost/parameter/binding.hpp b/include/boost/parameter/binding.hpp index 9204c8d..1d62c41 100755 --- a/include/boost/parameter/binding.hpp +++ b/include/boost/parameter/binding.hpp @@ -9,7 +9,11 @@ # include # include # include -# include +# include + +# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# include +# endif namespace boost { namespace parameter { @@ -33,6 +37,9 @@ struct binding_eti , is_same > )); +# if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) + BOOST_MPL_AUX_LAMBDA_SUPPORT(3,binding,(Parameters,Keyword,Default)) +# endif }; # if BOOST_WORKAROUND(BOOST_MSVC, < 1300) @@ -44,6 +51,8 @@ struct binding , mpl::identity , binding_eti >::type type; + + BOOST_MPL_AUX_LAMBDA_SUPPORT(3,binding,(Parameters,Keyword,Default)) }; # endif diff --git a/include/boost/parameter/name.hpp b/include/boost/parameter/name.hpp index 4b9627a..56bf40b 100755 --- a/include/boost/parameter/name.hpp +++ b/include/boost/parameter/name.hpp @@ -12,7 +12,21 @@ # include # include # include -# include + +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# include +// From Paul Mensonides +# define BOOST_PARAMETER_IS_BINARY(x) \ + BOOST_PP_SPLIT(1, BOOST_PARAMETER_IS_BINARY_C x BOOST_PP_COMMA() 0) \ + /**/ +# define BOOST_PARAMETER_IS_BINARY_C(x,y) \ + ~, 1 BOOST_PP_RPAREN() \ + BOOST_PP_TUPLE_EAT(2) BOOST_PP_LPAREN() ~ \ + /**/ +# else +# include +# define BOOST_PARAMETER_IS_BINARY(x) BOOST_PP_IS_BINARY(x) +# endif # if BOOST_WORKAROUND(BOOST_MSVC, < 1300) # define BOOST_PARAMETER_NAME_OBJECT(tag, name) \ @@ -65,7 +79,7 @@ # define BOOST_PARAMETER_NAME(name) \ BOOST_PP_IIF( \ - BOOST_PP_IS_BINARY(name) \ + BOOST_PARAMETER_IS_BINARY(name) \ , BOOST_PARAMETER_COMPLEX_NAME \ , BOOST_PARAMETER_SIMPLE_NAME \ )(name) \ diff --git a/include/boost/parameter/parameters.hpp b/include/boost/parameter/parameters.hpp index 5c5d013..41f63dd 100755 --- a/include/boost/parameter/parameters.hpp +++ b/include/boost/parameter/parameters.hpp @@ -8,6 +8,8 @@ #include +#include + #include #include #include @@ -43,6 +45,7 @@ #include #include #include +#include #include namespace boost { @@ -68,7 +71,7 @@ namespace aux { struct use_default {}; } // required<...>, wrapper, it is treated as though optional were // specified. // -// If a keyword k is specified with unnamed<...>, that keyword +// If a keyword k is specified with deduced<...>, that keyword // will be automatically deduced from the argument list. // template @@ -85,20 +88,37 @@ struct optional typedef Predicate predicate; }; -template -struct unnamed +template +struct deduced { typedef Tag key_type; - typedef Predicate predicate; }; namespace aux { // Defines metafunctions, is_required and is_optional, that - // identify required<...>, optional<...> and unnamed<...> specializations. + // identify required<...>, optional<...> and deduced<...> specializations. BOOST_DETAIL_IS_XXX_DEF(required, required, 2) BOOST_DETAIL_IS_XXX_DEF(optional, optional, 2) - BOOST_DETAIL_IS_XXX_DEF(unnamed, unnamed, 2) + BOOST_DETAIL_IS_XXX_DEF(deduced_aux, deduced, 1) + + template + struct is_deduced0 + : is_deduced_aux< + typename S::key_type + >::type + {}; + + template + struct is_deduced + : mpl::eval_if< + mpl::or_< + is_optional, is_required + > + , is_deduced0 + , mpl::false_ + >::type + {}; // // key_type, has_default, and predicate -- @@ -109,27 +129,36 @@ namespace aux // argument type is required match. // // a ParameterSpec is a specialization of either keyword<...>, - // required<...>, optional<...> or unnamed<...> + // required<...>, optional<...> // // helper for key_type<...>, below. template - struct get_key_type - { typedef typename T::key_type type; }; + struct get_tag_type0 + { + typedef typename T::key_type type; + }; template - struct key_type + struct get_tag_type + : mpl::eval_if< + is_deduced_aux + , get_tag_type0 + , mpl::identity + > + {}; + + template + struct tag_type : mpl::eval_if< mpl::or_< is_optional , is_required - , is_unnamed > - , get_key_type + , get_tag_type , mpl::identity > - { - }; + {}; template struct has_default @@ -164,7 +193,6 @@ namespace aux mpl::or_< is_optional , is_required - , is_unnamed > , get_predicate , mpl::identity > @@ -175,13 +203,13 @@ namespace aux // Converts a ParameterSpec into a specialization of // parameter_requirements. We need to do this in order to get the - // key_type into the type in a way that can be conveniently matched + // tag_type into the type in a way that can be conveniently matched // by a satisfies(...) member function in arg_list. template struct as_parameter_requirements { typedef parameter_requirements< - typename key_type::type + typename tag_type::type , typename predicate::type , typename has_default::type > type; @@ -195,27 +223,6 @@ namespace aux > {}; - // Labels Arg with default keyword tag DefaultTag if it is not - // already a tagged_argument. If an unnamed spec that matches - // Arg exists in UnnamedList, labels Arg with that spec's - // keyword tag. - template - struct as_tagged_argument - : mpl::eval_if< - is_named_argument - , mpl::identity > - , mpl::apply_wrap3 - > - {}; - -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) // ETI workaround - template <> - struct as_tagged_argument - { - typedef int type; - }; -#endif - // Returns mpl::true_ iff the given ParameterRequirements are // satisfied by ArgList. template @@ -263,52 +270,346 @@ namespace aux > {}; - // Helper for make_partial_arg_list, below. Produce an arg_list - // node for the given ParameterSpec and ArgumentType, whose tail is - // determined by invoking the nullary metafunction TailFn. - template - struct make_arg_list + // Tags a deduced argument Arg with the keyword tag of Spec using TagFn. + // Returns the tagged argument and the mpl::set<> UsedArgs with the + // tag of Spec inserted. + template + struct tag_deduced { - template - struct apply - { - typedef typename as_tagged_argument< - ParameterSpec,ArgumentType,UnnamedList,TagFn - >::type tagged_result; - - typedef arg_list< - typename mpl::first::type - , typename mpl::apply_wrap1< - TailFn, typename mpl::second::type - >::type - > type; - }; + typedef mpl::pair< + typename mpl::apply_wrap2::type, Arg>::type + , typename aux::insert_::type>::type + > type; }; - // Just like make_arg_list, except if ArgumentType is void_, the - // result is empty_arg_list. Used to build arg_lists whose length - // depends on the number of non-default (void_) arguments passed to - // a class template. template < - class ParameterSpec - , class ArgumentType + class Argument + , class ArgumentPack + , class DeducedArgs + , class UsedArgs , class TagFn - , class TailFn > - struct make_partial_arg_list + struct deduce_tag; + + + // Helper for deduce_tag<> below. + template < + class Argument + , class ArgumentPack + , class DeducedArgs + , class UsedArgs + , class TagFn + > + struct deduce_tag0 { - template - struct apply - { - typedef typename mpl::eval_if< - is_same - , mpl::identity - , mpl::apply_wrap1< - make_arg_list - , UnnamedList - > - >::type type; - }; + typedef typename DeducedArgs::spec spec; + + typedef typename mpl::apply2< + typename spec::predicate, Argument, ArgumentPack + >::type condition; + + // Deduced parameter matches several arguments. + + BOOST_MPL_ASSERT(( + mpl::not_::type> + > > + )); + + typedef typename mpl::eval_if< + condition + , tag_deduced + , deduce_tag + >::type type; + }; + + // Tries to deduced a keyword tag for a given Argument. + // Returns an mpl::pair<> consisting of the tagged_argument<>, + // and an mpl::set<> where the new tag has been inserted. + // + // Argument: The argument type to be tagged. + // + // ArgumentPack: The ArgumentPack built so far. + // + // DeducedArgs: A specialization of deduced_item<> (see below). + // A list containing only the deduced ParameterSpecs. + // + // UsedArgs: An mpl::set<> containing the keyword tags used so far. + // + // TagFn: A metafunction class used to tag positional or deduced + // arguments with a keyword tag. + + template < + class Argument + , class ArgumentPack + , class DeducedArgs + , class UsedArgs + , class TagFn + > + struct deduce_tag + { + typedef typename mpl::eval_if< + is_same + , mpl::pair + , deduce_tag0 + >::type type; + }; + + template < + class List + , class DeducedArgs + , class TagFn + , class Positional + , class UsedArgs + , class ArgumentPack + > + struct make_arg_list_aux; + + // Inserts Tagged::key_type into the UserArgs set. + // Extra indirection to lazily evaluate Tagged::key_type. + template + struct insert_tagged + { + typedef typename aux::insert_< + UsedArgs, typename Tagged::key_type + >::type type; + }; + + // Borland needs the insane extra-indirection workaround below + // so that it doesn't magically drop the const qualifier from + // the argument type. + + template < + class List + , class DeducedArgs + , class TagFn + , class Positional + , class UsedArgs + , class ArgumentPack +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + , class argument +#endif + > +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + struct make_arg_list00 +#else + struct make_arg_list0 +#endif + { +#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + typedef typename List::arg argument; +#endif + typedef typename List::spec parameter_spec; + typedef typename tag_type::type tag_; + + typedef is_named_argument is_tagged; + + // If this argument is either explicitly tagged or a deduced + // parameter, we turn off positional matching. + typedef mpl::and_< + mpl::not_< + mpl::or_, is_tagged> + > + , Positional + > positional; + + // If this parameter is explicitly tagged we add it to the + // used-parmeters set. We only really need to add parameters + // that are deduced, but we would need a way to check if + // a given tag corresponds to a deduced parameter spec. + typedef typename mpl::eval_if< + is_tagged + , insert_tagged + , mpl::identity + >::type used_args; + + // If this parameter is neither explicitly tagged, nor + // positionally matched; deduce the tag from the deduced + // parameter specs. + typedef typename mpl::eval_if< + mpl::or_ + , mpl::pair + , deduce_tag + >::type deduced_data; + + // If this parameter is explicitly tagged.. + typedef typename mpl::eval_if< + is_tagged + , mpl::identity // .. just use it + , mpl::eval_if< // .. else, if positional matching is turned on.. + positional + , mpl::apply_wrap2 // .. tag it positionally + , mpl::first // .. else, use the deduced tag + > + >::type tagged; + + // We build the arg_list incrementally as we go, prepending new + // nodes. + + // TODO. We should create a dummy node in the arg_list + // here. A node that swallows an argument in the constructor. + typedef typename mpl::if_< + is_same + , ArgumentPack + , arg_list + >::type argument_pack; + + typedef typename make_arg_list_aux< + typename List::tail + , DeducedArgs + , TagFn + , positional + , typename deduced_data::second + , argument_pack + >::type type; + }; + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + template < + class List + , class DeducedArgs + , class TagFn + , class Positional + , class UsedArgs + , class ArgumentPack + > + struct make_arg_list0 + { + typedef typename mpl::eval_if< + typename List::is_arg_const + , make_arg_list00< + List + , DeducedArgs + , TagFn + , Positional + , UsedArgs + , ArgumentPack + , typename List::arg const + > + , make_arg_list00< + List + , DeducedArgs + , TagFn + , Positional + , UsedArgs + , ArgumentPack + , typename List::arg + > + >::type type; + }; +#endif + + // Returns an ArgumentPack where the list of arguments has + // been tagged with keyword tags. + // + // List: A specialization of item<> (see below). Contains + // both the ordered ParameterSpecs, and the given arguments. + // + // DeducedArgs: A specialization of deduced_item<> (see below). + // A list containing only the deduced ParameterSpecs. + // + // TagFn: A metafunction class used to tag positional or deduced + // arguments with a keyword tag. + // + // Position: An mpl::bool_<> specialization indicating if positional + // matching is to be performed. + // + // DeducedSet: An mpl::set<> containing the keyword tags used so far. + // + // ArgumentPack: The ArgumentPack built so far. This is initially an + // empty_arg_list and is built incrementally. + // + + template < + class List + , class DeducedArgs + , class TagFn + , class Positional + , class DeducedSet + , class ArgumentPack + > + struct make_arg_list_aux + { + typedef typename mpl::eval_if< + is_same + , mpl::identity + , make_arg_list0 + >::type type; + }; + + // VC6.5 was choking on the default parameters for make_arg_list_aux, so + // this just forwards to that adding in the defaults. + template < + class List + , class DeducedArgs + , class TagFn + > + struct make_arg_list + { + typedef typename make_arg_list_aux< + List, DeducedArgs, TagFn, mpl::true_, aux::set0, empty_arg_list + >::type type; + }; + + // A parameter spec item typelist. + template + struct item + { + typedef Spec spec; + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + typedef is_const is_arg_const; +#endif + + typedef Arg arg; + typedef Tail tail; + }; + + template + struct make_item + { + typedef item type; + }; + + // Creates a item typelist. + template + struct make_items + { + typedef typename mpl::eval_if< + is_same + , mpl::identity + , make_item + >::type type; + }; + + // A typelist that stored deduced parameter specs. + template + struct deduced_item + { + typedef ParameterSpec spec; + typedef Tail tail; + }; + + // Evaluate Tail and construct deduced_item list. + template + struct make_deduced_item + { + typedef deduced_item type; + }; + + template + struct make_deduced_items + { + typedef typename mpl::eval_if< + is_same + , mpl::identity + , mpl::eval_if< + is_deduced + , make_deduced_item + , Tail + > + >::type type; }; // Generates: @@ -323,124 +624,24 @@ namespace aux #define BOOST_PARAMETER_make_arg_list(z, n, names) \ BOOST_PP_SEQ_ELEM(0,names)< \ BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names), n), \ - BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(2,names), n), \ - BOOST_PP_SEQ_ELEM(3,names), + BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(2,names), n), #define BOOST_PARAMETER_right_angle(z, n, text) > -#define BOOST_PARAMETER_build_arg_list(n, make, parameter_spec, argument_type, tag) \ +#define BOOST_PARAMETER_build_arg_list(n, make, parameter_spec, argument_type) \ BOOST_PP_REPEAT( \ - n, BOOST_PARAMETER_make_arg_list, (make)(parameter_spec)(argument_type)(tag)) \ - mpl::always \ + n, BOOST_PARAMETER_make_arg_list, (make)(parameter_spec)(argument_type)) \ + mpl::identity \ BOOST_PP_REPEAT(n, BOOST_PARAMETER_right_angle, _) - // Terminates an unnamed_list (below). - struct empty_unnamed_list - { - template - struct apply - { - // No unnamed predicate matched Arg, so we tag Arg with - // the DefaultTag. - - BOOST_MPL_ASSERT_NOT((is_unnamed)); - - typedef mpl::pair< - typename mpl::apply_wrap2< - TagFn - , typename key_type::type - , Arg - >::type - , empty_unnamed_list - > type; - }; - }; - - // Used by as_tagged_argument to match a given - // argument with a list of unnamed specs. - // - // ParameterSpec is an unnamed spec. - // Tail is either another unnamed_list specialization, - // or empty_unnamed_list. - template - struct unnamed_list - { - // Helper metafunction for apply below. Computes the result - // of Tail::apply. Returns a pair consisting of: - // - // * the tagged argument - // * the unnamed_list that is left after the tagging. Possibly - // with one element removed. - template - struct eval_tail - { - typedef typename mpl::apply_wrap3< - Tail, Arg, Positional, TagFn - >::type result; - - typedef mpl::pair< - typename mpl::first::type - , unnamed_list::type> - > type; - }; - - // If this keyword's predicate returns true for - // the given argument type, tag the argument with - // ParameterSpec::key_type. Otherwise try the tail. - template - struct apply - { - typedef typename mpl::eval_if< - typename mpl::apply1::type - , mpl::pair< - typename mpl::apply_wrap2< - TagFn, typename ParameterSpec::key_type, Arg - >::type - , Tail - > - , -#if BOOST_WORKAROUND(__GNUC__, < 3) - typename unnamed_list::template -#endif - eval_tail - >::type type; - }; - }; - - // We need to build a list of all ParameterSpec's that specify an - // unnamed argument. This list is used when trying to match an - // argument to an unnamed keyword. - - template - struct make_unnamed_list - { - typedef unnamed_list< - ParameterSpec - , typename TailFn::type - > type; - }; - - template - struct make_partial_unnamed_list - : mpl::eval_if< - is_same - , mpl::identity - , mpl::eval_if< - is_unnamed - , make_unnamed_list - , TailFn - > - > - {}; - -#define BOOST_PARAMETER_make_unnamed_list(z, n, names) \ +#define BOOST_PARAMETER_make_deduced_list(z, n, names) \ BOOST_PP_SEQ_ELEM(0,names)< \ BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names), n), - -#define BOOST_PARAMETER_build_unnamed_list(n, make, parameter_spec) \ + +#define BOOST_PARAMETER_build_deduced_list(n, make, parameter_spec) \ BOOST_PP_REPEAT( \ - n, BOOST_PARAMETER_make_unnamed_list, (make)(parameter_spec)) \ - mpl::identity \ + n, BOOST_PARAMETER_make_deduced_list, (make)(parameter_spec)) \ + mpl::identity \ BOOST_PP_REPEAT(n, BOOST_PARAMETER_right_angle, _) struct tag_keyword_arg @@ -479,9 +680,9 @@ struct parameters { #undef BOOST_PARAMETER_TEMPLATE_ARGS - typedef typename BOOST_PARAMETER_build_unnamed_list( - BOOST_PARAMETER_MAX_ARITY, aux::make_partial_unnamed_list, PS - )::type unnamed_list; + typedef typename BOOST_PARAMETER_build_deduced_list( + BOOST_PARAMETER_MAX_ARITY, aux::make_deduced_items, PS + )::type deduced_list; // if the elements of NamedList match the criteria of overload // resolution, returns a type which can be constructed from @@ -493,7 +694,7 @@ struct parameters // If NamedList satisfies the PS0, PS1, ..., this is a // metafunction returning parameters. Otherwise it // has no nested ::type. - template + template struct match_base : mpl::if_< // mpl::and_< @@ -505,7 +706,7 @@ struct parameters # define BOOST_PARAMETER_satisfies(z, n, text) \ mpl::and_< \ - aux::satisfies_requirements_of , + aux::satisfies_requirements_of , BOOST_PP_REPEAT(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_satisfies, _) mpl::true_ @@ -536,10 +737,13 @@ struct parameters struct match # ifndef BOOST_NO_SFINAE : match_base< - typename mpl::apply_wrap1::type + typename aux::make_arg_list< + typename BOOST_PARAMETER_build_arg_list( + BOOST_PARAMETER_MAX_ARITY, aux::make_items, PS, A + )::type + , deduced_list + , aux::tag_keyword_arg + >::type >::type {}; # else @@ -551,7 +755,7 @@ struct parameters # endif // Metafunction that returns an ArgumentPack. - + template < #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland simply can't handle default arguments in member @@ -566,10 +770,13 @@ struct parameters > struct bind { - typedef typename mpl::apply_wrap1::type type; + >::type type; }; BOOST_PARAMETER_FORWARD_TYPEDEFS(BOOST_PARAMETER_MAX_ARITY, PS, parameter_spec) @@ -579,21 +786,33 @@ struct parameters // labels the positional parameters and maintains whatever other // tags may have been specified by the caller. // + // !!!NOTE!!! + // + // The make_arg_list<> produces a reversed arg_list, so + // we need to pass the arguments to it's constructor + // reversed. + // aux::empty_arg_list operator()() const { return aux::empty_arg_list(); } template - typename mpl::apply_wrap1< - aux::make_arg_list > - , unnamed_list + typename aux::make_arg_list< + aux::item< + PS0,A0 + > + , void_ + , aux::tag_keyword_arg >::type operator()(A0& a0) const { - typedef typename mpl::apply_wrap1< - aux::make_arg_list > - , unnamed_list + typedef typename aux::make_arg_list< + aux::item< + PS0,A0 + > + , deduced_list + , aux::tag_keyword_arg >::type result_type; return result_type( @@ -606,31 +825,31 @@ struct parameters } template - typename mpl::apply_wrap1< - aux::make_arg_list< - PS0,A0,aux::tag_keyword_arg - , aux::make_arg_list< - PS1,A1,aux::tag_keyword_arg - , mpl::always + typename aux::make_arg_list< + aux::item< + PS0,A0 + , aux::item< + PS1,A1 > > - , unnamed_list + , deduced_list + , aux::tag_keyword_arg >::type operator()(A0& a0, A1& a1) const { - typedef typename mpl::apply_wrap1< - aux::make_arg_list< - PS0,A0,aux::tag_keyword_arg - , aux::make_arg_list< - PS1,A1,aux::tag_keyword_arg - , mpl::always + typedef typename aux::make_arg_list< + aux::item< + PS0,A0 + , aux::item< + PS1,A1 > > - , unnamed_list + , deduced_list + , aux::tag_keyword_arg >::type result_type; return result_type( - a0, a1 + a1,a0 // , void_(), void_() ... BOOST_PP_ENUM_TRAILING_PARAMS( BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, 2) diff --git a/include/boost/parameter/preprocessor.hpp b/include/boost/parameter/preprocessor.hpp index a67bc16..76c5f63 100755 --- a/include/boost/parameter/preprocessor.hpp +++ b/include/boost/parameter/preprocessor.hpp @@ -32,6 +32,10 @@ # include # include +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +# include +# endif + namespace boost { namespace parameter { namespace aux { # ifndef BOOST_NO_SFINAE @@ -93,6 +97,41 @@ struct match {}; # endif +# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) + +// Function template argument deduction does many of the same things +// as type matching during partial specialization, so we call a +// function template to "store" T into the type memory addressed by +// void(*)(T). +template +msvc_store_type +msvc_store_predicate_type(void*(*)(void**(T))); + +template +msvc_store_type,void*(*)(void*(T))> +msvc_store_predicate_type(void*(*)(void*(T))); + +template +struct unwrap_predicate +{ + static FunctionType f; + + // We don't want the function to be evaluated, just instantiated, + // so protect it inside of sizeof. + enum { dummy = sizeof(msvc_store_predicate_type(f)) }; + + // Now pull the type out of the instantiated base class + typedef typename msvc_type_memory::storage::type type; +}; + +template <> +struct unwrap_predicate +{ + typedef mpl::always type; +}; + +# endif + template < class Parameters , BOOST_PP_ENUM_BINARY_PARAMS( @@ -101,12 +140,12 @@ template < > struct argument_pack { - typedef typename mpl::apply_wrap1< - BOOST_PARAMETER_build_arg_list( - BOOST_PARAMETER_MAX_ARITY, aux::make_partial_arg_list - , typename Parameters::parameter_spec, A, aux::tag_keyword_arg - ) - , typename Parameters::unnamed_list + typedef typename make_arg_list< + typename BOOST_PARAMETER_build_arg_list( + BOOST_PARAMETER_MAX_ARITY, make_items, typename Parameters::parameter_spec, A + )::type + , typename Parameters::deduced_list + , tag_keyword_arg >::type type; }; @@ -125,6 +164,58 @@ T const& as_lvalue(T const& value, int) } # endif + +# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) \ + || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +template +struct apply_predicate +{ + BOOST_MPL_ASSERT(( + mpl::and_ + )); + + typedef typename mpl::if_< + typename mpl::apply2::type + , char + , int + >::type type; +}; + +template +struct funptr_predicate +{ + static P p; + + template + static typename apply_predicate::type + check_predicate(type, Args*, void**(*)(P0)); + + template + static typename mpl::if_< + is_convertible + , char + , int + >::type check_predicate(type, Args*, void*(*)(P0)); + + template + struct apply + { + BOOST_STATIC_CONSTANT(bool, result = + sizeof(check_predicate(boost::type(), (Args*)0, &p)) == 1 + ); + + typedef mpl::bool_::result> type; + }; +}; + +template <> +struct funptr_predicate + : mpl::always +{}; + +# endif + }}} // namespace boost::parameter::aux # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) @@ -182,7 +273,9 @@ T const& as_lvalue(T const& value, int) // Calculates [begin, end) arity range. # define BOOST_PARAMETER_ARITY_RANGE_M_optional(state) state +# define BOOST_PARAMETER_ARITY_RANGE_M_deduced_optional(state) state # define BOOST_PARAMETER_ARITY_RANGE_M_required(state) BOOST_PP_INC(state) +# define BOOST_PARAMETER_ARITY_RANGE_M_deduced_required(state) BOOST_PP_INC(state) # define BOOST_PARAMETER_ARITY_RANGE_M(s, state, x) \ BOOST_PP_CAT( \ @@ -388,34 +481,62 @@ T const& as_lvalue(T const& value, int) /**/ // Builds boost::parameter::parameters<> specialization -# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_optional(tag) \ + optional + +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_deduced_required(tag) \ + required + +# if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) && !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) +# define BOOST_PARAMETER_PREDICATE_TYPE(p) void*(*) (void* p) +# else +# define BOOST_PARAMETER_PREDICATE_TYPE(p) void p +# endif + # define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ BOOST_PP_COMMA_IF(i) \ - boost::parameter::BOOST_PARAMETER_FN_ARG_QUALIFIER(elem)< \ + boost::parameter::BOOST_PP_CAT( \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_ \ + , BOOST_PARAMETER_FN_ARG_QUALIFIER(elem) \ + )( \ tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ BOOST_PARAMETER_FN_ARG_KEYWORD(elem) \ ) \ + ) \ , typename boost::parameter::aux::unwrap_predicate< \ - void BOOST_PARAMETER_FN_ARG_PRED(elem) \ + BOOST_PARAMETER_PREDICATE_TYPE(BOOST_PARAMETER_FN_ARG_PRED(elem)) \ >::type \ > # else # define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ BOOST_PP_COMMA_IF(i) \ - boost::parameter::BOOST_PARAMETER_FN_ARG_QUALIFIER(elem)< \ + boost::parameter::BOOST_PP_CAT( \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_ \ + , BOOST_PARAMETER_FN_ARG_QUALIFIER(elem) \ + )( \ tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ BOOST_PARAMETER_FN_ARG_KEYWORD(elem) \ ) \ - , boost::mpl::always \ + ) \ + , boost::parameter::aux::funptr_predicate< \ + void* BOOST_PARAMETER_FN_ARG_PRED(elem) \ + > \ > # endif -/**/ # define BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, base, args) \ - template \ - struct BOOST_PP_CAT( \ - BOOST_PP_CAT(boost_param_params_, __LINE__) \ - , BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base) \ + template \ + struct BOOST_PP_CAT( \ + BOOST_PP_CAT(boost_param_params_, __LINE__) \ + , BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base) \ ) : boost::parameter::parameters< \ BOOST_PP_SEQ_FOR_EACH_I( \ BOOST_PARAMETER_FUNCTION_PARAMETERS_M, tag_namespace, args \ @@ -474,6 +595,9 @@ T const& as_lvalue(T const& value, int) , BOOST_PP_TUPLE_ELEM(4, 3, state) \ ) +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_deduced_required(state, arg) \ + BOOST_PARAMETER_FUNCTION_SPLIT_ARG_required(state, arg) + # define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_optional(state, arg) \ ( \ BOOST_PP_TUPLE_ELEM(4, 0, state) \ @@ -482,6 +606,9 @@ T const& as_lvalue(T const& value, int) , BOOST_PP_SEQ_PUSH_BACK(BOOST_PP_TUPLE_ELEM(4, 3, state), arg) \ ) +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_deduced_optional(state, arg) \ + BOOST_PARAMETER_FUNCTION_SPLIT_ARG_optional(state, arg) + # define BOOST_PARAMETER_FUNCTION_SPLIT_ARG(s, state, arg) \ BOOST_PP_CAT( \ BOOST_PARAMETER_FUNCTION_SPLIT_ARG_ \ @@ -919,7 +1046,7 @@ T const& as_lvalue(T const& value, int) ) /**/ -# if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING # define BOOST_PARAMETER_FUNCTION_FWD_COMBINATION(r, _, i, elem) \ (BOOST_PP_IF( \ BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER( \ @@ -928,6 +1055,18 @@ T const& as_lvalue(T const& value, int) , (const ParameterArgumentType ## i)(ParameterArgumentType ## i) \ , (const ParameterArgumentType ## i) \ )) +// MSVC6.5 lets us bind rvalues to T&. +# elif BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# define BOOST_PARAMETER_FUNCTION_FWD_COMBINATION(r, _, i, elem) \ + (BOOST_PP_IF( \ + BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER( \ + BOOST_PARAMETER_FN_ARG_NAME(elem) \ + ) \ + , (ParameterArgumentType ## i) \ + , (const ParameterArgumentType ## i) \ + )) +// No partial ordering. This feature doesn't work. +// This is exactly the same as for VC6.5, but we might change it later. # else # define BOOST_PARAMETER_FUNCTION_FWD_COMBINATION(r, _, i, elem) \ (BOOST_PP_IF( \ diff --git a/include/boost/parameter/python.hpp b/include/boost/parameter/python.hpp index 252ec03..a52fc6e 100755 --- a/include/boost/parameter/python.hpp +++ b/include/boost/parameter/python.hpp @@ -25,6 +25,7 @@ # include # include # include +# include # include # include # include diff --git a/test/Jamfile b/test/Jamfile index 5901b70..d15e46e 100755 --- a/test/Jamfile +++ b/test/Jamfile @@ -19,24 +19,27 @@ test-suite "parameter" [ run singular.cpp ] [ run mpl.cpp ] [ run preprocessor.cpp ] + [ run preprocessor_deduced.cpp ] [ run efficiency.cpp : : : : : release ] [ run maybe.cpp ] + [ run deduced.cpp ] [ compile ntp.cpp ] [ compile unwrap_cv_reference.cpp ] [ compile-fail duplicates.cpp ] [ compile-fail unnamed_fail.cpp ] [ compile compose.cpp ] + [ compile normalized_argument_types.cpp ] ; import python ; -extension python_parameter - : python.cpp +extension python_test_ext + : python_test.cpp