]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [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 | |
27 | objects. It forwards RValues as references to const, while leaving LValues | |
28 | as-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 | ||
42 | Another adapter, `boost::lighweight_forward_adapter` allows forwarding with | |
43 | some help from the user accepting and unwrapping reference wrappers (see | |
44 | __boost_ref__) for reference arguments, const qualifying all other arguments. | |
45 | ||
46 | The target functions must be compatible with __boost_result_of__, and so are | |
47 | the adapters. | |
48 | ||
49 | [endsect] | |
50 | ||
51 | [section Background] | |
52 | ||
53 | Let's suppose we have some function `f` that we can call like this: | |
54 | ||
55 | f(123,a_variable); | |
56 | ||
57 | Now we want to write another, generic function `g` that can be called the | |
58 | same 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 | ||
64 | Maybe we want to run `f` several times. Or maybe we want to run it within | |
65 | another thread. Maybe we just want to encapsulate the call expression for now, | |
66 | and then use it with other code that allows to compose more complex expressions | |
67 | in order to decompose it with C++ templates and have the compiler generate some | |
68 | machinery that eventually calls `f` at runtime (in other words; apply a | |
69 | technique that is commonly referred to as Expression Templates). | |
70 | ||
71 | [heading Now, how do we do it?] | |
72 | ||
73 | The bad news is: It's impossible. | |
74 | ||
75 | That is so because there is a slight difference between a variable and an | |
76 | expression that evaluates to its value: Given | |
77 | ||
78 | int y; | |
79 | int const z = 0; | |
80 | ||
81 | and | |
82 | ||
83 | template< typename T > void func1(T & x); | |
84 | ||
85 | we 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 | ||
90 | where | |
91 | ||
92 | func1(1); // fails to compile. | |
93 | ||
94 | This way we can safely have `func1` store its reference argument and the | |
95 | compiler keeps us from storing a reference to an object with temporary lifetime. | |
96 | ||
97 | It is important to realize that non-constness and whether an object binds to a | |
98 | non-const reference parameter are two different properties. The latter is the | |
99 | distinction between LValues and RValues. The names stem from the left hand side | |
100 | and the right hand side of assignment expressions, thus LValues are typically | |
101 | the ones you can assign to, and RValues the temporary results from the right | |
102 | hand 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 | ||
110 | If we add const qualification on the parameter, our function also accepts | |
111 | RValues: | |
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 | ||
120 | In all cases, the argument `x` in `func2` is a const-qualified LValue. | |
121 | We 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 | ||
131 | Note that all arguments `x` in the overloaded function `func3` are LValues. | |
132 | In fact, there is no way to transport RValues into a function as-is in C++98. | |
133 | Also note that we can't distinguish between what used to be a const qualified | |
134 | LValue and an RValue. | |
135 | ||
136 | That's as close as we can get to a generic forwarding function `g` as | |
137 | described above by the means of C++ 98. See __the_forwarding_problem__ for a | |
138 | very detailed discussion including solutions that require language changes. | |
139 | ||
140 | Now, 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 | |
143 | is O(2^N), however the factor is low so it works quite well for a reasonable | |
144 | number (< 10) of arguments. | |
145 | ||
146 | [endsect] | |
147 | ||
148 | [section:reference Reference] | |
149 | ||
150 | [section forward_adapter] | |
151 | ||
152 | [heading Description] | |
153 | ||
154 | Function object adapter template whose instances are callable with LValue and | |
155 | RValue arguments. RValue arguments are forwarded as reference-to-const typed | |
156 | LValues. | |
157 | ||
158 | An arity can be given as second, numeric non-type template argument to restrict | |
159 | forwarding to a specific arity. | |
160 | If a third, numeric non-type template argument is present, the second and third | |
161 | template argument are treated as minimum and maximum arity, respectively. | |
162 | Specifying an arity can be helpful to improve the readability of diagnostic | |
163 | messages and compile time performance. | |
164 | ||
165 | __boost_result_of__ can be used to determine the result types of specific call | |
166 | expressions. | |
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 | ||
188 | The result type of a target function invocation must be | |
189 | ||
190 | __boost__result_of__<F*(TA0 [const]&...TAN [const]&])>::type | |
191 | ||
192 | where `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 | ||
205 | The macro BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY can be defined to set the | |
206 | maximum call arity. It defaults to 6. | |
207 | ||
208 | [heading Complexity] | |
209 | ||
210 | Preprocessing time: O(2^N), where N is the arity limit. | |
211 | Compile time: O(2^N), where N depends on the arity range. | |
212 | Run 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 | ||
221 | Function object adapter template whose instances are callable with LValue and | |
222 | RValue arguments. All arguments are forwarded as reference-to-const typed | |
223 | LValues, except for reference wrappers which are unwrapped and may yield | |
224 | non-const LValues. | |
225 | ||
226 | An arity can be given as second, numeric non-type template argument to restrict | |
227 | forwarding to a specific arity. | |
228 | If a third, numeric non-type template argument is present, the second and third | |
229 | template argument are treated as minimum and maximum arity, respectively. | |
230 | Specifying an arity can be helpful to improve the readability of diagnostic | |
231 | messages and compile time performance. | |
232 | ||
233 | __boost_result_of__ can be used to determine the result types of specific call | |
234 | expressions. | |
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 | ||
256 | The result type of a target function invocation must be | |
257 | ||
258 | __boost__result_of__<F*(TA0 [const]&...TAN [const]&])>::type | |
259 | ||
260 | where `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 | ||
274 | The macro BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY can be defined | |
275 | to set the maximum call arity. It defaults to 10. | |
276 | ||
277 | [heading Complexity] | |
278 | ||
279 | Preprocessing time: O(N), where N is the arity limit. | |
280 | Compile time: O(N), where N is the effective arity of a call. | |
281 | Run time: O(0) if the compiler inlines, O(1) otherwise. | |
282 | ||
283 | [endsect] | |
284 | ||
285 | [endsect] | |
286 | ||
287 | ||
288 | [section Acknowledgements] | |
289 | ||
290 | As these utilities are factored out of the __boost_fusion__ functional module, | |
291 | I want to thank Dan Marsden and Joel de Guzman for letting me participate in the | |
292 | development of that great library in the first place. | |
293 | ||
294 | Further, I want to credit the authors of the references below, for their | |
295 | in-depth investigation of the problem and the solution implemented here. | |
296 | ||
297 | Last but not least I want to thank Vesa Karnoven and Paul Mensonides for the | |
298 | Boost Preprocessor library. Without it, I would have ended up with an external | |
299 | code 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 |