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