]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 = void, | |
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 Changes] | |
355 | ||
356 | [heading Boost 1.58.0] | |
357 | ||
358 | In order to remove the dependency on Boost.Optional, the default parameter | |
359 | for allocators has been changed from `boost::none_t` to `void`. | |
360 | If you have code that has stopped working because it uses `boost::none_t`, | |
361 | a quick fix is to define `BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T`, which will | |
362 | restore support, but this will be removed in a future release. | |
363 | It should be be relatively easy to fix this properly. | |
364 | ||
365 | [endsect] | |
366 | ||
367 | [section Acknowledgements] | |
368 | ||
369 | Eric Niebler requested a function to invoke a type's constructor (with the | |
370 | arguments supplied as a Tuple) as a Fusion feature. These Factory utilities are | |
371 | a factored-out generalization of this idea. | |
372 | ||
373 | Dave Abrahams suggested Smart Pointer support for exception safety, providing | |
374 | useful hints for the implementation. | |
375 | ||
376 | Joel de Guzman's documentation style was copied from Fusion. | |
377 | ||
378 | Further, I want to thank Peter Dimov for sharing his insights on language | |
379 | details and their evolution. | |
380 | ||
381 | [endsect] | |
382 | ||
383 | [section References] | |
384 | ||
385 | # [@http://en.wikipedia.org/wiki/Design_Patterns Design Patterns], | |
386 | Gamma et al. - Addison Wesley Publishing, 1995 | |
387 | ||
388 | # [@http://www.sgi.com/tech/stl/ Standard Template Library Programmer's Guide], | |
389 | Hewlett-Packard Company, 1994 | |
390 | ||
391 | # [@http://www.boost.org/libs/bind/bind.html Boost.Bind], | |
392 | Peter Dimov, 2001-2005 | |
393 | ||
394 | # [@http://www.boost.org/doc/html/function.html Boost.Function], | |
395 | Douglas Gregor, 2001-2004 | |
396 | ||
397 | [endsect] | |
398 | ||
399 |