diff --git a/doc/named_params.rst b/doc/named_params.rst index 8a9e02b..d57f7a3 100755 --- a/doc/named_params.rst +++ b/doc/named_params.rst @@ -105,6 +105,8 @@ First we define the named parameter keywords. This is done by creating "tag" types for each keyword, and declaring ``keyword<``\ *tag*\ ``>`` objects:: + #include + struct name_t; // tag types struct value_t; @@ -209,107 +211,141 @@ Now compiles, and prints:: bar = 0 unnamed = 3 -``reference_wrapper<>`` -======================= +Limitations of the Approach +=========================== -Our forwarding functions need to take their parameters by const -reference. This is because we need to be able to pass the temporaries -created from the operator= call. Because of this, passing non-const -references that aren't bound to a keyword isn't possible without some help. +Because the keywords' ``operator=`` returns a temporary, and +temporaries cannot be bound to non-``const`` reference parameters, +our forwarding functions need to take their arguments by ``const`` +reference [#forwarding]_. As a result, an argument which is bound +to a keyword with ``operator=`` can be transparently passed by +non-const reference, but positional arguments are always passed by +``const`` reference unless we use the `Boost.Ref`_ library to +indicate otherwise:: -.. DWA What is "something something ?" supposed to mean? -.. It's was suppose to mean "more?".. - -:: + #include float x; - foo(value = x); // held type is float& - foo(x); // held type is float const&, need help! - foo(ref(x)); // held type is float& + foo(value = x); // held type is float& + foo(x); // held type is float const&, need help! + foo(boost::ref(x)); // held type is float& -Instances of boost::reference_wrapper<> will un unwrapped to it's held -reference type. +.. _`Boost.Ref`: ../../bind/ref.hpp -SFINAE restrictions -=================== -Sometimes it is necessary to restrict the types on which the forwarding -functions can be instantiated. This can be accomplished in C++ by using -SFINAE [#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. -This technique is formalized in the ``enable_if`` pattern [#enable_if]_. +Instances of ``boost::reference_wrapper<>`` generated by +``boost::ref`` will be unwrapped automatically by the library. -.. [#sfinae] Substitution Failure Is Not An Error. Some discussion - of SFINAE goes here. +Controlling Overload Resolution +=============================== -.. [#enable_if] Some discussion of ``enable_if`` goes here. +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 somehow remove the +functions from the overload set when the passed argument types +don't meet their needs. - .. more? +__ http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#225 -.. DWA What about tutorial for your macro? - Daniel: Under BOOST_NAMED_PARAMS_FUN(), should it be moved? - or do we need a more verbose tutorial? +This overload control can be accomplished in C++ by taking +advantage of SFINAE_ (Substitution Failure Is Not An Error). If +type substitution during the instantiation of a function template +results in an invalid type, no compilation error is emitted; +instead the overload is removed from the overload set. By producing +an invalid type in the function signature depending on the result +of some condition, whether or not an overload is considered during +overload resolution can be controlled. This technique is +formalized in the |enable_if| utility. -Let's say we want to restrict our ``foo()`` so that the ``name`` -parameter must be convertible to ``const char*``. - -:: +The named parameters library provides built-in SFINAE support +through the following class template:: template< - class Keyword - , class HasDefaultValue + class KeywordTag + , class HasDefaultValue // mpl::true_ or mpl::false_ , class Predicate > struct arg; -:: +The key parameter, ``Predicate`` shall be a unary MPL lambda +expression or `Metafunction Class`_ that, when applied to the +actual type the argument, indicates whether that argument type +meets the function's requirements for that parameter position. + +.. _`Metafunction Class`: ../../mpl/doc/ref/Metafunction_Class.html + +.. _SFINAE: http://www.semantics.org/once_weakly/w02_SFINAE.pdf + +.. |enable_if| replace:: ``enable_if`` +.. _enable_if: ../enable_if.html + +For example, let's say we want to restrict our ``foo()`` so that +the ``name`` parameter must be convertible to ``const char*``. +We'll replace our use of the ``name_t`` tag with a specialization +of ``boost::arg``: + +.. parsed-literal:: struct foo_keywords - : keywords< - arg< - name_t - , mpl::false_ - , is_convertible - > - , value_t - > + : boost::keywords< + **boost::arg< + name_t + , mpl::false\_ + , is_convertible + >** + , value_t + > {}; -:: +Now we can add an additional optional argument to each of our +``foo`` overloads + +.. parsed-literal:: template - void foo(const A0& a0 - , foo_keywords::restrict::type x = foo_keywords()) + void foo( + const A0& a0 + , **foo_keywords::restrict::type x = foo_keywords()** + ) { foo_impl(x(a0)); } template - void foo(const A0& a0, const A1& a1 - , foo_keywords::restrict::type x = foo_keywords()) + void foo( + const A0& a0, const A1& a1 + , **foo_keywords::restrict::type x = foo_keywords()** + ) { foo_impl(x(a0, a1)); } -``BOOST_NAMED_PARAMS_FUN()`` -============================ +These additional parameters are not intended to be used directly +by callers; they merely trigger SFINAE by becoming illegal types +when the ``name`` argument is not convertible to ``const char*``. -To reduce the work needed to write functions which has named parameters, +Automatic Overload Generation +============================= + +To reduce the work needed to write functions with named parameters, we supply a macro that generates the boilerplate code. Synopsis:: - BOOST_NAMED_PARAMS( + BOOST_NAMED_PARAMS_FUN( return_type, function_name, keywords_type , min_arity, max_arity ); -Applying this to our original example, we get:: +To generate all the forwarding functions and the implementation +function for our example, we need only apply +``BOOST_NAMED_PARAMS_FUN`` like this:: BOOST_NAMED_PARAMS_FUN(void, foo, foo_keywords, 0, 2) { @@ -318,3 +354,27 @@ Applying this to our original example, we get:: << parms[value | 0] << "\n"; } +----------------------------- + +.. [#forwarding] One could provide overloads for ``const`` and + non-``const`` reference versions of each parameter, but that + would quickly become unmanageable. It's known as "the + forwarding problem" and has been described in detail in this + paper__. The combinatorial explosion is avoided for the + parameter of keywords' ``operator=`` because they take only a + single argument. + + __ http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm + + +.. [#using] You can always give the illusion that the function + lives in an outer namespace by applying a *using-declaration*:: + + namespace foo_overloads + { + // foo declarations here + void foo() { ... } + ... + } + using foo_overloads::foo; +