blob: 4eb227da200c305bddfbd1ae718e85853ac03bc6 [file] [log] [blame]
Jeff Thompsona28eed82013-08-22 16:21:10 -07001[library Boost.Functional/Forward
2 [quickbook 1.3]
3 [version 1.0]
4 [authors [Schwinger, Tobias]]
5 [copyright 2007 2008 Tobias Schwinger]
6 [license
7 Distributed under the Boost Software License, Version 1.0.
8 (See accompanying file LICENSE_1_0.txt or copy at
9 [@http://www.boost.org/LICENSE_1_0.txt])
10 ]
11 [purpose Function object adapters for generic argument forwarding.]
12 [category higher-order]
13 [category generic]
14 [last-revision $Date: 2008/11/01 19:58:50 $]
15]
16
17[def __unspecified__ /unspecified/]
18[def __boost_ref__ [@http://www.boost.org/doc/html/ref.html Boost.Ref]]
19[def __boost_result_of__ [@http://www.boost.org/libs/utility/utility.htm#result_of Boost.ResultOf]]
20[def __boost__result_of__ [@http://www.boost.org/libs/utility/utility.htm#result_of `boost::result_of`]]
21[def __the_forwarding_problem__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm The Forwarding Problem]]
22[def __boost_fusion__ [@http://www.boost.org/libs/fusion/doc/html/index.html Boost.Fusion]]
23
24[section Brief Description]
25
26`boost::forward_adapter` provides a reusable adapter template for function
27objects. It forwards RValues as references to const, while leaving LValues
28as-is.
29
30 struct g // function object that only accept LValues
31 {
32 template< typename T0, typename T1, typename T2 >
33 void operator()(T0 & t0, T1 & t1, T2 & t2) const;
34
35 typedef void result_type;
36 };
37
38 // Adapted version also accepts RValues and forwards
39 // them as references to const, LValues as-is
40 typedef boost::forward_adapter<g> f;
41
42Another adapter, `boost::lighweight_forward_adapter` allows forwarding with
43some help from the user accepting and unwrapping reference wrappers (see
44__boost_ref__) for reference arguments, const qualifying all other arguments.
45
46The target functions must be compatible with __boost_result_of__, and so are
47the adapters.
48
49[endsect]
50
51[section Background]
52
53Let's suppose we have some function `f` that we can call like this:
54
55 f(123,a_variable);
56
57Now we want to write another, generic function `g` that can be called the
58same way and returns some object that calls `f` with the same arguments.
59
60 f(123,a_variable) == g(f,123,a_variable).call_f()
61
62[heading Why would we want to do it, anyway?]
63
64Maybe we want to run `f` several times. Or maybe we want to run it within
65another thread. Maybe we just want to encapsulate the call expression for now,
66and then use it with other code that allows to compose more complex expressions
67in order to decompose it with C++ templates and have the compiler generate some
68machinery that eventually calls `f` at runtime (in other words; apply a
69technique that is commonly referred to as Expression Templates).
70
71[heading Now, how do we do it?]
72
73The bad news is: It's impossible.
74
75That is so because there is a slight difference between a variable and an
76expression that evaluates to its value: Given
77
78 int y;
79 int const z = 0;
80
81and
82
83 template< typename T > void func1(T & x);
84
85we can call
86
87 func1(y); // x is a reference to a non-const object
88 func1(z); // x is a reference to a const object
89
90where
91
92 func1(1); // fails to compile.
93
94This way we can safely have `func1` store its reference argument and the
95compiler keeps us from storing a reference to an object with temporary lifetime.
96
97It is important to realize that non-constness and whether an object binds to a
98non-const reference parameter are two different properties. The latter is the
99distinction between LValues and RValues. The names stem from the left hand side
100and the right hand side of assignment expressions, thus LValues are typically
101the ones you can assign to, and RValues the temporary results from the right
102hand side expression.
103
104 y = 1+2; // a is LValue, 1+2 is the expression producing the RValue,
105 // 1+2 = a; // usually makes no sense.
106
107 func1(y); // works, because y is an LValue
108 // func1(1+2); // fails to compile, because we only got an RValue.
109
110If we add const qualification on the parameter, our function also accepts
111RValues:
112
113 template< typename T > void func2(T const & x);
114
115 // [...] function scope:
116 func2(1); // x is a reference to a const temporary, object,
117 func2(y); // x is a reference to a const object, while y is not const, and
118 func2(z); // x is a reference to a const object, just like z.
119
120In all cases, the argument `x` in `func2` is a const-qualified LValue.
121We can use function overloading to identify non-const LValues:
122
123 template< typename T > void func3(T const & x); // #1
124 template< typename T > void func3(T & x); // #2
125
126 // [...] function scope:
127 func3(1); // x is a reference to a const, temporary object in #1,
128 func3(y); // x is a reference to a non-const object in #2, and
129 func3(z); // x is a reference to a const object in #1.
130
131Note that all arguments `x` in the overloaded function `func3` are LValues.
132In fact, there is no way to transport RValues into a function as-is in C++98.
133Also note that we can't distinguish between what used to be a const qualified
134LValue and an RValue.
135
136That's as close as we can get to a generic forwarding function `g` as
137described above by the means of C++ 98. See __the_forwarding_problem__ for a
138very detailed discussion including solutions that require language changes.
139
140Now, for actually implementing it, we need 2^N overloads for N parameters
141(each with and without const qualifier) for each number of arguments
142(that is 2^(Nmax+1) - 2^Nmin). Right, that means the compile-time complexity
143is O(2^N), however the factor is low so it works quite well for a reasonable
144number (< 10) of arguments.
145
146[endsect]
147
148[section:reference Reference]
149
150[section forward_adapter]
151
152[heading Description]
153
154Function object adapter template whose instances are callable with LValue and
155RValue arguments. RValue arguments are forwarded as reference-to-const typed
156LValues.
157
158An arity can be given as second, numeric non-type template argument to restrict
159forwarding to a specific arity.
160If a third, numeric non-type template argument is present, the second and third
161template argument are treated as minimum and maximum arity, respectively.
162Specifying an arity can be helpful to improve the readability of diagnostic
163messages and compile time performance.
164
165__boost_result_of__ can be used to determine the result types of specific call
166expressions.
167
168[heading Header]
169 #include <boost/functional/forward_adapter.hpp>
170
171[heading Synopsis]
172
173 namespace boost
174 {
175 template< class Function,
176 int Arity_Or_MinArity = __unspecified__, int MaxArity = __unspecified__ >
177 class forward_adapter;
178 }
179
180[variablelist Notation
181 [[`F`] [a possibly const qualified function object type or reference type thereof]]
182 [[`f`] [an object convertible to `F`]]
183 [[`FA`] [the type `forward_adapter<F>`]]
184 [[`fa`] [an instance object of `FA`, initialized with `f`]]
185 [[`a0`...`aN`] [arguments to `fa`]]
186]
187
188The result type of a target function invocation must be
189
190 __boost__result_of__<F*(TA0 [const]&...TAN [const]&])>::type
191
192where `TA0`...`TAN` denote the argument types of `a0`...`aN`.
193
194[heading Expression Semantics]
195
196[table
197 [[Expression] [Semantics]]
198 [[`FA(f)`] [creates an adapter, initializes the target function with `f`.]]
199 [[`FA()`] [creates an adapter, attempts to use `F`'s default constructor.]]
200 [[`fa(a0`...`aN)`] [calls `f` with with arguments `a0`...`aN`.]]
201]
202
203[heading Limits]
204
205The macro BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY can be defined to set the
206maximum call arity. It defaults to 6.
207
208[heading Complexity]
209
210Preprocessing time: O(2^N), where N is the arity limit.
211Compile time: O(2^N), where N depends on the arity range.
212Run time: O(0) if the compiler inlines, O(1) otherwise.
213
214[endsect]
215
216
217[section lightweight_forward_adapter]
218
219[heading Description]
220
221Function object adapter template whose instances are callable with LValue and
222RValue arguments. All arguments are forwarded as reference-to-const typed
223LValues, except for reference wrappers which are unwrapped and may yield
224non-const LValues.
225
226An arity can be given as second, numeric non-type template argument to restrict
227forwarding to a specific arity.
228If a third, numeric non-type template argument is present, the second and third
229template argument are treated as minimum and maximum arity, respectively.
230Specifying an arity can be helpful to improve the readability of diagnostic
231messages and compile time performance.
232
233__boost_result_of__ can be used to determine the result types of specific call
234expressions.
235
236[heading Header]
237 #include <boost/functional/lightweight_forward_adapter.hpp>
238
239[heading Synopsis]
240
241 namespace boost
242 {
243 template< class Function,
244 int Arity_Or_MinArity = __unspecified__, int MaxArity = __unspecified__ >
245 struct lightweight_forward_adapter;
246 }
247
248[variablelist Notation
249 [[`F`] [a possibly const qualified function object type or reference type thereof]]
250 [[`f`] [an object convertible to `F`]]
251 [[`FA`] [the type `lightweight_forward_adapter<F>`]]
252 [[`fa`] [an instance of `FA`, initialized with `f`]]
253 [[`a0`...`aN`] [arguments to `fa`]]
254]
255
256The result type of a target function invocation must be
257
258 __boost__result_of__<F*(TA0 [const]&...TAN [const]&])>::type
259
260where `TA0`...`TAN` denote the argument types of `a0`...`aN`.
261
262[heading Expression Semantics]
263
264[table
265 [[Expression] [Semantics]]
266 [[`FA(f)`] [creates an adapter, initializes the target function with `f`.]]
267 [[`FA()`] [creates an adapter, attempts to use `F`'s default constructor.]]
268 [[`fa(a0`...`aN)`] [calls `f` with with const arguments `a0`...`aN`. If `aI` is a
269 reference wrapper it is unwrapped.]]
270]
271
272[heading Limits]
273
274The macro BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY can be defined
275to set the maximum call arity. It defaults to 10.
276
277[heading Complexity]
278
279Preprocessing time: O(N), where N is the arity limit.
280Compile time: O(N), where N is the effective arity of a call.
281Run time: O(0) if the compiler inlines, O(1) otherwise.
282
283[endsect]
284
285[endsect]
286
287
288[section Acknowledgements]
289
290As these utilities are factored out of the __boost_fusion__ functional module,
291I want to thank Dan Marsden and Joel de Guzman for letting me participate in the
292development of that great library in the first place.
293
294Further, I want to credit the authors of the references below, for their
295in-depth investigation of the problem and the solution implemented here.
296
297Last but not least I want to thank Vesa Karnoven and Paul Mensonides for the
298Boost Preprocessor library. Without it, I would have ended up with an external
299code generator for this one.
300
301[endsect]
302
303
304[section References]
305
306# [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm The Forwarding Problem],
307 Peter Dimov, Howard E. Hinnant, David Abrahams, 2002
308
309# [@http://www.boost.org/libs/utility/utility.htm#result_of Boost.ResultOf],
310 Douglas Gregor, 2004
311
312# [@http://www.boost.org/doc/html/ref.html Boost.Ref],
313 Jaakko Jarvi, Peter Dimov, Douglas Gregor, David Abrahams, 1999-2002
314
315[endsect]
316