3cec009503
[SVN r61597]
317 lines
11 KiB
Plaintext
317 lines
11 KiB
Plaintext
[library Boost.Functional/Forward
|
|
[quickbook 1.3]
|
|
[version 1.0]
|
|
[authors [Schwinger, Tobias]]
|
|
[copyright 2007 2008 Tobias Schwinger]
|
|
[license
|
|
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])
|
|
]
|
|
[purpose Function object adapters for generic argument forwarding.]
|
|
[category higher-order]
|
|
[category generic]
|
|
[last-revision $Date: 2008/11/01 19:58:50 $]
|
|
]
|
|
|
|
[def __unspecified__ /unspecified/]
|
|
[def __boost_ref__ [@http://www.boost.org/doc/html/ref.html Boost.Ref]]
|
|
[def __boost_result_of__ [@http://www.boost.org/libs/utility/utility.htm#result_of Boost.ResultOf]]
|
|
[def __boost__result_of__ [@http://www.boost.org/libs/utility/utility.htm#result_of `boost::result_of`]]
|
|
[def __the_forwarding_problem__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm The Forwarding Problem]]
|
|
[def __boost_fusion__ [@http://www.boost.org/libs/fusion/doc/html/index.html Boost.Fusion]]
|
|
|
|
[section Brief Description]
|
|
|
|
`boost::forward_adapter` provides a reusable adapter template for function
|
|
objects. It forwards RValues as references to const, while leaving LValues
|
|
as-is.
|
|
|
|
struct g // function object that only accept LValues
|
|
{
|
|
template< typename T0, typename T1, typename T2 >
|
|
void operator()(T0 & t0, T1 & t1, T2 & t2) const;
|
|
|
|
typedef void result_type;
|
|
};
|
|
|
|
// Adapted version also accepts RValues and forwards
|
|
// them as references to const, LValues as-is
|
|
typedef boost::forward_adapter<g> f;
|
|
|
|
Another adapter, `boost::lighweight_forward_adapter` allows forwarding with
|
|
some help from the user accepting and unwrapping reference wrappers (see
|
|
__boost_ref__) for reference arguments, const qualifying all other arguments.
|
|
|
|
The target functions must be compatible with __boost_result_of__, and so are
|
|
the adapters.
|
|
|
|
[endsect]
|
|
|
|
[section Background]
|
|
|
|
Let's suppose we have some function `f` that we can call like this:
|
|
|
|
f(123,a_variable);
|
|
|
|
Now we want to write another, generic function `g` that can be called the
|
|
same way and returns some object that calls `f` with the same arguments.
|
|
|
|
f(123,a_variable) == g(f,123,a_variable).call_f()
|
|
|
|
[heading Why would we want to do it, anyway?]
|
|
|
|
Maybe we want to run `f` several times. Or maybe we want to run it within
|
|
another thread. Maybe we just want to encapsulate the call expression for now,
|
|
and then use it with other code that allows to compose more complex expressions
|
|
in order to decompose it with C++ templates and have the compiler generate some
|
|
machinery that eventually calls `f` at runtime (in other words; apply a
|
|
technique that is commonly referred to as Expression Templates).
|
|
|
|
[heading Now, how do we do it?]
|
|
|
|
The bad news is: It's impossible.
|
|
|
|
That is so because there is a slight difference between a variable and an
|
|
expression that evaluates to its value: Given
|
|
|
|
int y;
|
|
int const z = 0;
|
|
|
|
and
|
|
|
|
template< typename T > void func1(T & x);
|
|
|
|
we can call
|
|
|
|
func1(y); // x is a reference to a non-const object
|
|
func1(z); // x is a reference to a const object
|
|
|
|
where
|
|
|
|
func1(1); // fails to compile.
|
|
|
|
This way we can safely have `func1` store its reference argument and the
|
|
compiler keeps us from storing a reference to an object with temporary lifetime.
|
|
|
|
It is important to realize that non-constness and whether an object binds to a
|
|
non-const reference parameter are two different properties. The latter is the
|
|
distinction between LValues and RValues. The names stem from the left hand side
|
|
and the right hand side of assignment expressions, thus LValues are typically
|
|
the ones you can assign to, and RValues the temporary results from the right
|
|
hand side expression.
|
|
|
|
y = 1+2; // a is LValue, 1+2 is the expression producing the RValue,
|
|
// 1+2 = a; // usually makes no sense.
|
|
|
|
func1(y); // works, because y is an LValue
|
|
// func1(1+2); // fails to compile, because we only got an RValue.
|
|
|
|
If we add const qualification on the parameter, our function also accepts
|
|
RValues:
|
|
|
|
template< typename T > void func2(T const & x);
|
|
|
|
// [...] function scope:
|
|
func2(1); // x is a reference to a const temporary, object,
|
|
func2(y); // x is a reference to a const object, while y is not const, and
|
|
func2(z); // x is a reference to a const object, just like z.
|
|
|
|
In all cases, the argument `x` in `func2` is a const-qualified LValue.
|
|
We can use function overloading to identify non-const LValues:
|
|
|
|
template< typename T > void func3(T const & x); // #1
|
|
template< typename T > void func3(T & x); // #2
|
|
|
|
// [...] function scope:
|
|
func3(1); // x is a reference to a const, temporary object in #1,
|
|
func3(y); // x is a reference to a non-const object in #2, and
|
|
func3(z); // x is a reference to a const object in #1.
|
|
|
|
Note that all arguments `x` in the overloaded function `func3` are LValues.
|
|
In fact, there is no way to transport RValues into a function as-is in C++98.
|
|
Also note that we can't distinguish between what used to be a const qualified
|
|
LValue and an RValue.
|
|
|
|
That's as close as we can get to a generic forwarding function `g` as
|
|
described above by the means of C++ 98. See __the_forwarding_problem__ for a
|
|
very detailed discussion including solutions that require language changes.
|
|
|
|
Now, for actually implementing it, we need 2^N overloads for N parameters
|
|
(each with and without const qualifier) for each number of arguments
|
|
(that is 2^(Nmax+1) - 2^Nmin). Right, that means the compile-time complexity
|
|
is O(2^N), however the factor is low so it works quite well for a reasonable
|
|
number (< 10) of arguments.
|
|
|
|
[endsect]
|
|
|
|
[section:reference Reference]
|
|
|
|
[section forward_adapter]
|
|
|
|
[heading Description]
|
|
|
|
Function object adapter template whose instances are callable with LValue and
|
|
RValue arguments. RValue arguments are forwarded as reference-to-const typed
|
|
LValues.
|
|
|
|
An arity can be given as second, numeric non-type template argument to restrict
|
|
forwarding to a specific arity.
|
|
If a third, numeric non-type template argument is present, the second and third
|
|
template argument are treated as minimum and maximum arity, respectively.
|
|
Specifying an arity can be helpful to improve the readability of diagnostic
|
|
messages and compile time performance.
|
|
|
|
__boost_result_of__ can be used to determine the result types of specific call
|
|
expressions.
|
|
|
|
[heading Header]
|
|
#include <boost/functional/forward_adapter.hpp>
|
|
|
|
[heading Synopsis]
|
|
|
|
namespace boost
|
|
{
|
|
template< class Function,
|
|
int Arity_Or_MinArity = __unspecified__, int MaxArity = __unspecified__ >
|
|
class forward_adapter;
|
|
}
|
|
|
|
[variablelist Notation
|
|
[[`F`] [a possibly const qualified function object type or reference type thereof]]
|
|
[[`f`] [an object convertible to `F`]]
|
|
[[`FA`] [the type `forward_adapter<F>`]]
|
|
[[`fa`] [an instance object of `FA`, initialized with `f`]]
|
|
[[`a0`...`aN`] [arguments to `fa`]]
|
|
]
|
|
|
|
The result type of a target function invocation must be
|
|
|
|
__boost__result_of__<F*(TA0 [const]&...TAN [const]&])>::type
|
|
|
|
where `TA0`...`TAN` denote the argument types of `a0`...`aN`.
|
|
|
|
[heading Expression Semantics]
|
|
|
|
[table
|
|
[[Expression] [Semantics]]
|
|
[[`FA(f)`] [creates an adapter, initializes the target function with `f`.]]
|
|
[[`FA()`] [creates an adapter, attempts to use `F`'s default constructor.]]
|
|
[[`fa(a0`...`aN)`] [calls `f` with with arguments `a0`...`aN`.]]
|
|
]
|
|
|
|
[heading Limits]
|
|
|
|
The macro BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY can be defined to set the
|
|
maximum call arity. It defaults to 6.
|
|
|
|
[heading Complexity]
|
|
|
|
Preprocessing time: O(2^N), where N is the arity limit.
|
|
Compile time: O(2^N), where N depends on the arity range.
|
|
Run time: O(0) if the compiler inlines, O(1) otherwise.
|
|
|
|
[endsect]
|
|
|
|
|
|
[section lightweight_forward_adapter]
|
|
|
|
[heading Description]
|
|
|
|
Function object adapter template whose instances are callable with LValue and
|
|
RValue arguments. All arguments are forwarded as reference-to-const typed
|
|
LValues, except for reference wrappers which are unwrapped and may yield
|
|
non-const LValues.
|
|
|
|
An arity can be given as second, numeric non-type template argument to restrict
|
|
forwarding to a specific arity.
|
|
If a third, numeric non-type template argument is present, the second and third
|
|
template argument are treated as minimum and maximum arity, respectively.
|
|
Specifying an arity can be helpful to improve the readability of diagnostic
|
|
messages and compile time performance.
|
|
|
|
__boost_result_of__ can be used to determine the result types of specific call
|
|
expressions.
|
|
|
|
[heading Header]
|
|
#include <boost/functional/lightweight_forward_adapter.hpp>
|
|
|
|
[heading Synopsis]
|
|
|
|
namespace boost
|
|
{
|
|
template< class Function,
|
|
int Arity_Or_MinArity = __unspecified__, int MaxArity = __unspecified__ >
|
|
struct lightweight_forward_adapter;
|
|
}
|
|
|
|
[variablelist Notation
|
|
[[`F`] [a possibly const qualified function object type or reference type thereof]]
|
|
[[`f`] [an object convertible to `F`]]
|
|
[[`FA`] [the type `lightweight_forward_adapter<F>`]]
|
|
[[`fa`] [an instance of `FA`, initialized with `f`]]
|
|
[[`a0`...`aN`] [arguments to `fa`]]
|
|
]
|
|
|
|
The result type of a target function invocation must be
|
|
|
|
__boost__result_of__<F*(TA0 [const]&...TAN [const]&])>::type
|
|
|
|
where `TA0`...`TAN` denote the argument types of `a0`...`aN`.
|
|
|
|
[heading Expression Semantics]
|
|
|
|
[table
|
|
[[Expression] [Semantics]]
|
|
[[`FA(f)`] [creates an adapter, initializes the target function with `f`.]]
|
|
[[`FA()`] [creates an adapter, attempts to use `F`'s default constructor.]]
|
|
[[`fa(a0`...`aN)`] [calls `f` with with const arguments `a0`...`aN`. If `aI` is a
|
|
reference wrapper it is unwrapped.]]
|
|
]
|
|
|
|
[heading Limits]
|
|
|
|
The macro BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY can be defined
|
|
to set the maximum call arity. It defaults to 10.
|
|
|
|
[heading Complexity]
|
|
|
|
Preprocessing time: O(N), where N is the arity limit.
|
|
Compile time: O(N), where N is the effective arity of a call.
|
|
Run time: O(0) if the compiler inlines, O(1) otherwise.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Acknowledgements]
|
|
|
|
As these utilities are factored out of the __boost_fusion__ functional module,
|
|
I want to thank Dan Marsden and Joel de Guzman for letting me participate in the
|
|
development of that great library in the first place.
|
|
|
|
Further, I want to credit the authors of the references below, for their
|
|
in-depth investigation of the problem and the solution implemented here.
|
|
|
|
Last but not least I want to thank Vesa Karnoven and Paul Mensonides for the
|
|
Boost Preprocessor library. Without it, I would have ended up with an external
|
|
code generator for this one.
|
|
|
|
[endsect]
|
|
|
|
|
|
[section References]
|
|
|
|
# [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm The Forwarding Problem],
|
|
Peter Dimov, Howard E. Hinnant, David Abrahams, 2002
|
|
|
|
# [@http://www.boost.org/libs/utility/utility.htm#result_of Boost.ResultOf],
|
|
Douglas Gregor, 2004
|
|
|
|
# [@http://www.boost.org/doc/html/ref.html Boost.Ref],
|
|
Jaakko Jarvi, Peter Dimov, Douglas Gregor, David Abrahams, 1999-2002
|
|
|
|
[endsect]
|
|
|