Jeff Thompson | a28eed8 | 2013-08-22 16:21:10 -0700 | [diff] [blame^] | 1 | [library Boost.Functional/Factory |
| 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 templates for object creation.] |
| 12 | [category higher-order] |
| 13 | [category generic] |
| 14 | [last-revision $Date: 2008/11/01 21:44:52 $] |
| 15 | ] |
| 16 | |
| 17 | [def __boost_bind__ [@http://www.boost.org/libs/bind/bind.html Boost.Bind]] |
| 18 | [def __boost__bind__ [@http://www.boost.org/libs/bind/bind.html `boost::bind`]] |
| 19 | |
| 20 | [def __boost__forward_adapter__ [@http://www.boost.org/libs/functional/forward/doc/index.html `boost::forward_adapter`]] |
| 21 | [def __fusion_functional_adapters__ [@http://www.boost.org/libs/fusion/doc/html/functional.html Fusion Functional Adapters]] |
| 22 | |
| 23 | [def __boost_function__ [@http://www.boost.org/doc/html/function.html Boost.Function]] |
| 24 | [def __boost__function__ [@http://www.boost.org/doc/html/function.html `boost::function`]] |
| 25 | |
| 26 | [def __smart_pointer__ [@http://www.boost.org/libs/smart_ptr/index.html Smart Pointer]] |
| 27 | [def __smart_pointers__ [@http://www.boost.org/libs/smart_ptr/index.html Smart Pointers]] |
| 28 | [def __boost__shared_ptr__ [@http://www.boost.org/libs/smart_ptr/shared_ptr.htm `boost::shared_ptr`]] |
| 29 | |
| 30 | [def __std__map__ [@http://www.sgi.com/tech/stl/map.html `std::map`]] |
| 31 | [def __std__string__ [@http://www.sgi.com/tech/stl/string.html `std::string`]] |
| 32 | [def __allocator__ [@http://www.sgi.com/tech/stl/concepts/allocator.html Allocator]] |
| 33 | [def __std_allocator__ [@http://www.sgi.com/tech/stl/concepts/allocator.html Allocator]] |
| 34 | [def __std_allocators__ [@http://www.sgi.com/tech/stl/concepts/allocator.html Allocators]] |
| 35 | |
| 36 | [def __boost__ptr_map__ [@http://www.boost.org/libs/ptr_container/doc/ptr_map.html `boost::ptr_map`]] |
| 37 | |
| 38 | [def __boost__factory__ `boost::factory`] |
| 39 | [def __boost__value_factory__ `boost::value_factory`] |
| 40 | |
| 41 | [def __factory__ `factory`] |
| 42 | [def __value_factory__ `value_factory`] |
| 43 | |
| 44 | |
| 45 | [section Brief Description] |
| 46 | |
| 47 | The template __boost__factory__ lets you encapsulate a `new` expression |
| 48 | as a function object, __boost__value_factory__ encapsulates a constructor |
| 49 | invocation without `new`. |
| 50 | |
| 51 | __boost__factory__<T*>()(arg1,arg2,arg3) |
| 52 | // same as new T(arg1,arg2,arg3) |
| 53 | |
| 54 | __boost__value_factory__<T>()(arg1,arg2,arg3) |
| 55 | // same as T(arg1,arg2,arg3) |
| 56 | |
| 57 | For technical reasons the arguments to the function objects have to be |
| 58 | LValues. A factory that also accepts RValues can be composed using the |
| 59 | __boost__forward_adapter__ or __boost__bind__. |
| 60 | |
| 61 | [endsect] |
| 62 | |
| 63 | [section Background] |
| 64 | |
| 65 | In traditional Object Oriented Programming a Factory is an object implementing |
| 66 | an interface of one or more methods that construct objects conforming to known |
| 67 | interfaces. |
| 68 | |
| 69 | // assuming a_concrete_class and another_concrete_class are derived |
| 70 | // from an_abstract_class |
| 71 | |
| 72 | class a_factory |
| 73 | { |
| 74 | public: |
| 75 | virtual an_abstract_class* create() const = 0; |
| 76 | virtual ~a_factory() { } |
| 77 | }; |
| 78 | |
| 79 | class a_concrete_factory : public a_factory |
| 80 | { |
| 81 | public: |
| 82 | virtual an_abstract_class* create() const |
| 83 | { |
| 84 | return new a_concrete_class(); |
| 85 | } |
| 86 | }; |
| 87 | |
| 88 | class another_concrete_factory : public a_factory |
| 89 | { |
| 90 | public: |
| 91 | virtual an_abstract_class* create() const |
| 92 | { |
| 93 | return new another_concrete_class(); |
| 94 | } |
| 95 | }; |
| 96 | |
| 97 | // [...] |
| 98 | |
| 99 | int main() |
| 100 | { |
| 101 | __boost__ptr_map__<__std__string__,a_factory> factories; |
| 102 | |
| 103 | // [...] |
| 104 | |
| 105 | factories.insert("a_name",std::auto_ptr<a_factory>( |
| 106 | new a_concrete_factory)); |
| 107 | factories.insert("another_name",std::auto_ptr<a_factory>( |
| 108 | new another_concrete_factory)); |
| 109 | |
| 110 | // [...] |
| 111 | |
| 112 | std::auto_ptr<an_abstract_class> x(factories.at(some_name).create()); |
| 113 | |
| 114 | // [...] |
| 115 | } |
| 116 | |
| 117 | This approach has several drawbacks. The most obvious one is that there is |
| 118 | lots of boilerplate code. In other words there is too much code to express |
| 119 | a rather simple intention. We could use templates to get rid of some of it |
| 120 | but the approach remains inflexible: |
| 121 | |
| 122 | * We may want a factory that takes some arguments that are forwarded to |
| 123 | the constructor, |
| 124 | * we will probably want to use smart pointers, |
| 125 | * we may want several member functions to create different kinds of |
| 126 | objects, |
| 127 | * we might not necessarily need a polymorphic base class for the objects, |
| 128 | * as we will see, we do not need a factory base class at all, |
| 129 | * we might want to just call the constructor - without `new` to create |
| 130 | an object on the stack, and |
| 131 | * finally we might want to use customized memory management. |
| 132 | |
| 133 | Experience has shown that using function objects and generic Boost components |
| 134 | for their composition, Design Patterns that describe callback mechanisms |
| 135 | (typically requiring a high percentage of boilerplate code with pure Object |
| 136 | Oriented methodology) become implementable with just few code lines and without |
| 137 | extra classes. |
| 138 | |
| 139 | Factories are callback mechanisms for constructors, so we provide two class |
| 140 | templates, __boost__value_factory__ and __boost__factory__, that encapsulate |
| 141 | object construction via direct application of the constructor and the `new` |
| 142 | operator, respectively. |
| 143 | |
| 144 | We let the function objects forward their arguments to the construction |
| 145 | expressions they encapsulate. Over this __boost__factory__ optionally allows |
| 146 | the use of smart pointers and __std_allocators__. |
| 147 | |
| 148 | Compile-time polymorphism can be used where appropriate, |
| 149 | |
| 150 | template< class T > |
| 151 | void do_something() |
| 152 | { |
| 153 | // [...] |
| 154 | T x = T(a,b); |
| 155 | |
| 156 | // for conceptually similar objects x we neither need virtual |
| 157 | // functions nor a common base class in this context. |
| 158 | // [...] |
| 159 | } |
| 160 | |
| 161 | Now, to allow inhomogeneous signatures for the constructors of the types passed |
| 162 | in for `T` we can use __value_factory__ and __boost__bind__ to normalize between |
| 163 | them. |
| 164 | |
| 165 | template< class ValueFactory > |
| 166 | void do_something(ValueFactory make_obj = ValueFactory()) |
| 167 | { |
| 168 | // [...] |
| 169 | typename ValueFactory::result_type x = make_obj(a,b); |
| 170 | |
| 171 | // for conceptually similar objects x we neither need virtual |
| 172 | // functions nor a common base class in this context. |
| 173 | // [...] |
| 174 | } |
| 175 | |
| 176 | int main() |
| 177 | { |
| 178 | // [...] |
| 179 | |
| 180 | do_something(__boost__value_factory__<X>()); |
| 181 | do_something(boost::bind(__boost__value_factory__<Y>(),_1,5,_2)); |
| 182 | // construct X(a,b) and Y(a,5,b), respectively. |
| 183 | |
| 184 | // [...] |
| 185 | } |
| 186 | |
| 187 | Maybe we want our objects to outlive the function's scope, in this case we |
| 188 | have to use dynamic allocation; |
| 189 | |
| 190 | template< class Factory > |
| 191 | whatever do_something(Factory new_obj = Factory()) |
| 192 | { |
| 193 | typename Factory::result_type ptr = new_obj(a,b); |
| 194 | |
| 195 | // again, no common base class or virtual functions needed, |
| 196 | // we could enforce a polymorphic base by writing e.g. |
| 197 | // boost::shared_ptr<base> |
| 198 | // instead of |
| 199 | // typename Factory::result_type |
| 200 | // above. |
| 201 | // Note that we are also free to have the type erasure happen |
| 202 | // somewhere else (e.g. in the constructor of this function's |
| 203 | // result type). |
| 204 | |
| 205 | // [...] |
| 206 | } |
| 207 | |
| 208 | // [... call do_something like above but with __factory__ instead |
| 209 | // of __value_factory__] |
| 210 | |
| 211 | Although we might have created polymorphic objects in the previous example, |
| 212 | we have used compile time polymorphism for the factory. If we want to erase |
| 213 | the type of the factory and thus allow polymorphism at run time, we can |
| 214 | use __boost_function__ to do so. The first example can be rewritten as |
| 215 | follows. |
| 216 | |
| 217 | typedef boost::function< an_abstract_class*() > a_factory; |
| 218 | |
| 219 | // [...] |
| 220 | |
| 221 | int main() |
| 222 | { |
| 223 | __std__map__<__std__string__,a_factory> factories; |
| 224 | |
| 225 | // [...] |
| 226 | |
| 227 | factories["a_name"] = __boost__factory__<a_concrete_class*>(); |
| 228 | factories["another_name"] = |
| 229 | __boost__factory__<another_concrete_class*>(); |
| 230 | |
| 231 | // [...] |
| 232 | } |
| 233 | |
| 234 | Of course we can just as easy create factories that take arguments and/or |
| 235 | return __smart_pointers__. |
| 236 | |
| 237 | [endsect] |
| 238 | |
| 239 | |
| 240 | [section:reference Reference] |
| 241 | |
| 242 | |
| 243 | [section value_factory] |
| 244 | |
| 245 | [heading Description] |
| 246 | |
| 247 | Function object template that invokes the constructor of the type `T`. |
| 248 | |
| 249 | [heading Header] |
| 250 | #include <boost/functional/value_factory.hpp> |
| 251 | |
| 252 | [heading Synopsis] |
| 253 | |
| 254 | namespace boost |
| 255 | { |
| 256 | template< typename T > |
| 257 | class value_factory; |
| 258 | } |
| 259 | |
| 260 | [variablelist Notation |
| 261 | [[`T`] [an arbitrary type with at least one public constructor]] |
| 262 | [[`a0`...`aN`] [argument LValues to a constructor of `T`]] |
| 263 | [[`F`] [the type `value_factory<F>`]] |
| 264 | [[`f`] [an instance object of `F`]] |
| 265 | ] |
| 266 | |
| 267 | [heading Expression Semantics] |
| 268 | |
| 269 | [table |
| 270 | [[Expression] [Semantics]] |
| 271 | [[`F()`] [creates an object of type `F`.]] |
| 272 | [[`F(f)`] [creates an object of type `F`.]] |
| 273 | [[`f(a0`...`aN)`] [returns `T(a0`...`aN)`.]] |
| 274 | [[`F::result_type`] [is the type `T`.]] |
| 275 | ] |
| 276 | |
| 277 | [heading Limits] |
| 278 | |
| 279 | The macro BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY can be defined to set the |
| 280 | maximum arity. It defaults to 10. |
| 281 | |
| 282 | [endsect] |
| 283 | |
| 284 | |
| 285 | [section factory] |
| 286 | |
| 287 | [heading Description] |
| 288 | |
| 289 | Function object template that dynamically constructs a pointee object for |
| 290 | the type of pointer given as template argument. Smart pointers may be used |
| 291 | for the template argument, given that `boost::pointee<Pointer>::type` yields |
| 292 | the pointee type. |
| 293 | |
| 294 | If an __allocator__ is given, it is used for memory allocation and the |
| 295 | placement form of the `new` operator is used to construct the object. |
| 296 | A function object that calls the destructor and deallocates the memory |
| 297 | with a copy of the Allocator is used for the second constructor argument |
| 298 | of `Pointer` (thus it must be a __smart_pointer__ that provides a suitable |
| 299 | constructor, such as __boost__shared_ptr__). |
| 300 | |
| 301 | If a third template argument is `factory_passes_alloc_to_smart_pointer`, |
| 302 | the allocator itself is used for the third constructor argument of `Pointer` |
| 303 | (__boost__shared_ptr__ then uses the allocator to manage the memory of its |
| 304 | separately allocated reference counter). |
| 305 | |
| 306 | [heading Header] |
| 307 | #include <boost/functional/factory.hpp> |
| 308 | |
| 309 | [heading Synopsis] |
| 310 | |
| 311 | namespace boost |
| 312 | { |
| 313 | enum factory_alloc_propagation |
| 314 | { |
| 315 | factory_alloc_for_pointee_and_deleter, |
| 316 | factory_passes_alloc_to_smart_pointer |
| 317 | }; |
| 318 | |
| 319 | template< typename Pointer, |
| 320 | class Allocator = boost::none_t, |
| 321 | factory_alloc_propagation AllocProp = |
| 322 | factory_alloc_for_pointee_and_deleter > |
| 323 | class factory; |
| 324 | } |
| 325 | |
| 326 | [variablelist Notation |
| 327 | [[`T`] [an arbitrary type with at least one public constructor]] |
| 328 | [[`P`] [pointer or smart pointer to `T`]] |
| 329 | [[`a0`...`aN`] [argument LValues to a constructor of `T`]] |
| 330 | [[`F`] [the type `factory<P>`]] |
| 331 | [[`f`] [an instance object of `F`]] |
| 332 | ] |
| 333 | |
| 334 | [heading Expression Semantics] |
| 335 | |
| 336 | [table |
| 337 | [[Expression] [Semantics]] |
| 338 | [[`F()`] [creates an object of type `F`.]] |
| 339 | [[`F(f)`] [creates an object of type `F`.]] |
| 340 | [[`f(a0`...`aN)`] [dynamically creates an object of type `T` using |
| 341 | `a0`...`aN` as arguments for the constructor invocation.]] |
| 342 | [[`F::result_type`] [is the type `P` with top-level cv-qualifiers removed.]] |
| 343 | ] |
| 344 | |
| 345 | [heading Limits] |
| 346 | |
| 347 | The macro BOOST_FUNCTIONAL_FACTORY_MAX_ARITY can be defined to set the |
| 348 | maximum arity. It defaults to 10. |
| 349 | |
| 350 | [endsect] |
| 351 | |
| 352 | [endsect] |
| 353 | |
| 354 | [section Acknowledgements] |
| 355 | |
| 356 | Eric Niebler requested a function to invoke a type's constructor (with the |
| 357 | arguments supplied as a Tuple) as a Fusion feature. These Factory utilities are |
| 358 | a factored-out generalization of this idea. |
| 359 | |
| 360 | Dave Abrahams suggested Smart Pointer support for exception safety, providing |
| 361 | useful hints for the implementation. |
| 362 | |
| 363 | Joel de Guzman's documentation style was copied from Fusion. |
| 364 | |
| 365 | Further, I want to thank Peter Dimov for sharing his insights on language |
| 366 | details and their evolution. |
| 367 | |
| 368 | [endsect] |
| 369 | |
| 370 | [section References] |
| 371 | |
| 372 | # [@http://en.wikipedia.org/wiki/Design_Patterns Design Patterns], |
| 373 | Gamma et al. - Addison Wesley Publishing, 1995 |
| 374 | |
| 375 | # [@http://www.sgi.com/tech/stl/ Standard Template Library Programmer's Guide], |
| 376 | Hewlett-Packard Company, 1994 |
| 377 | |
| 378 | # [@http://www.boost.org/libs/bind/bind.html Boost.Bind], |
| 379 | Peter Dimov, 2001-2005 |
| 380 | |
| 381 | # [@http://www.boost.org/doc/html/function.html Boost.Function], |
| 382 | Douglas Gregor, 2001-2004 |
| 383 | |
| 384 | [endsect] |
| 385 | |
| 386 | |