123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- [/
- Copyright 2007,2008 Tobias Schwinger
- Copyright 2019 Glen Joseph Fernandes
- (glenjofe@gmail.com)
- Distributed under the Boost Software License, Version 1.0.
- (http://www.boost.org/LICENSE_1_0.txt)
- ]
- [library Boost.Functional/Factory
- [quickbook 1.5]
- [version 1.0]
- [authors [Schwinger, Tobias], [Fernandes, Glen]]
- [copyright 2007 2008 Tobias Schwinger]
- [copyright 2019 Glen Joseph Fernandes]
- [license Distributed under the Boost Software License, Version 1.0.]
- [purpose Function object templates for object creation.]
- [category higher-order]
- [category generic]]
- [def __boost__bind__
- [@http://www.boost.org/libs/bind/bind.html `boost::bind`]]
- [def __boost__forward_adapter__
- [@http://www.boost.org/libs/functional/forward/doc/index.html
- `boost::forward_adapter`]]
- [def __boost_function__
- [@http://www.boost.org/doc/html/function.html Boost.Function]]
- [def __smart_pointer__
- [@http://www.boost.org/libs/smart_ptr/index.html Smart Pointer]]
- [def __smart_pointers__
- [@http://www.boost.org/libs/smart_ptr/index.html Smart Pointers]]
- [def __boost__shared_ptr__
- [@http://www.boost.org/libs/smart_ptr/shared_ptr.htm `boost::shared_ptr`]]
- [def __allocator__ [@https://www.boost.org/sgi/stl/Allocators.html Allocator]]
- [def __std_allocators__
- [@https://www.boost.org/sgi/stl/Allocators.html Allocators]]
- [def __boost__factory__ `boost::factory`]
- [def __boost__value_factory__ `boost::value_factory`]
- [def __value_factory__ `value_factory`]
- [section Brief Description]
- The template __boost__factory__ lets you encapsulate a `new` expression as a
- function object, __boost__value_factory__ encapsulates a constructor invocation
- without `new`.
- ```
- __boost__factory__<T*>()(arg1,arg2,arg3)
- // same as new T(arg1,arg2,arg3)
- __boost__value_factory__<T>()(arg1,arg2,arg3)
- // same as T(arg1,arg2,arg3)
- ```
- Before C++11 the arguments to the function objects have to be LValues. A
- factory that also accepts RValues can be composed using the
- __boost__forward_adapter__ or __boost__bind__. In C++11 or higher the
- arguments can be LValues or RValues.
- [endsect]
- [section Background]
- In traditional Object Oriented Programming a Factory is an object implementing
- an interface of one or more methods that construct objects conforming to known
- interfaces.
- ```
- // assuming a_concrete_class and another_concrete_class are derived
- // from an_abstract_class
- struct a_factory {
- virtual an_abstract_class* create() const = 0;
- virtual ~a_factory() { }
- };
- struct a_concrete_factory
- : a_factory {
- an_abstract_class* create() const {
- return new a_concrete_class();
- }
- };
- struct another_concrete_factory
- : a_factory {
- an_abstract_class* create() const {
- return new another_concrete_class();
- }
- };
- // [...]
- int main()
- {
- boost::ptr_map<std::string, a_factory> factories;
- // [...]
- factories.insert("a_name",
- std::unique_ptr<a_factory>(new a_concrete_factory));
- factories.insert("another_name",
- std::unique_ptr<a_factory>(new another_concrete_factory));
- // [...]
- std::unique_ptr<an_abstract_class> x(factories.at(some_name).create());
- // [...]
- }
- ```
- This approach has several drawbacks. The most obvious one is that there is lots
- of boilerplate code. In other words there is too much code to express a rather
- simple intention. We could use templates to get rid of some of it but the
- approach remains inflexible:
- * We may want a factory that takes some arguments that are forwarded to the
- constructor,
- * we will probably want to use smart pointers,
- * we may want several member functions to create different kinds of objects,
- * we might not necessarily need a polymorphic base class for the objects,
- * as we will see, we do not need a factory base class at all,
- * we might want to just call the constructor - without `new` to create an
- object on the stack, and
- * finally we might want to use customized memory management.
- Experience has shown that using function objects and generic Boost components
- for their composition, Design Patterns that describe callback mechanisms
- (typically requiring a high percentage of boilerplate code with pure Object
- Oriented methodology) become implementable with just few code lines and without
- extra classes.
- Factories are callback mechanisms for constructors, so we provide two class
- templates, __boost__value_factory__ and __boost__factory__, that encapsulate
- object construction via direct application of the constructor and the `new`
- operator, respectively.
- We let the function objects forward their arguments to the construction
- expressions they encapsulate. Over this __boost__factory__ optionally allows
- the use of smart pointers and __std_allocators__.
- Compile-time polymorphism can be used where appropriate,
- ```
- template<class T>
- void do_something()
- {
- // [...]
- T x = T(a, b);
- // for conceptually similar objects x we neither need virtual
- // functions nor a common base class in this context.
- // [...]
- }
- ```
- Now, to allow inhomogeneous signatures for the constructors of the types passed
- in for `T` we can use __value_factory__ and __boost__bind__ to normalize
- between them.
- ```
- template<class ValueFactory>
- void do_something(ValueFactory make_obj = ValueFactory())
- {
- // [...]
- typename ValueFactory::result_type x = make_obj(a, b);
- // for conceptually similar objects x we neither need virtual
- // functions nor a common base class in this context.
- // [...]
- }
- int main()
- {
- // [...]
- do_something(boost::value_factory<X>());
- do_something(boost::bind(boost::value_factory<Y>(), _1, 5, _2));
- // construct X(a, b) and Y(a, 5, b), respectively.
- // [...]
- }
- ```
- Maybe we want our objects to outlive the function's scope, in this case we have
- to use dynamic allocation;
- ```
- template<class Factory>
- whatever do_something(Factory new_obj = Factory())
- {
- typename Factory::result_type ptr = new_obj(a, b);
- // again, no common base class or virtual functions needed,
- // we could enforce a polymorphic base by writing e.g.
- // boost::shared_ptr<base>
- // instead of
- // typename Factory::result_type
- // above.
- // Note that we are also free to have the type erasure happen
- // somewhere else (e.g. in the constructor of this function's
- // result type).
- // [...]
- }
- // [... call do_something like above but with boost::factory instead
- // of boost::value_factory]
- ```
- Although we might have created polymorphic objects in the previous example, we
- have used compile time polymorphism for the factory. If we want to erase the
- type of the factory and thus allow polymorphism at run time, we can use
- __boost_function__ to do so. The first example can be rewritten as follows.
- ```
- typedef boost::function<an_abstract_class*()> a_factory;
- // [...]
- int main()
- {
- std::map<std::string, a_factory> factories;
- // [...]
- factories["a_name"] = boost::factory<a_concrete_class*>();
- factories["another_name"] = boost::factory<another_concrete_class*>();
- // [...]
- }
- ```
- Of course we can just as easy create factories that take arguments and/or
- return __smart_pointers__.
- [endsect]
- [section:reference Reference]
- [section value_factory]
- [heading Description]
- Function object template that invokes the constructor of the type `T`.
- [heading Header]
- ```
- #include <boost/functional/value_factory.hpp>
- ```
- [heading Synopsis]
- ```
- namespace boost {
- template<class T>
- class value_factory;
- } // boost
- ```
- [variablelist Notation
- [[`T`][an arbitrary type with at least one public constructor]]
- [[`a0`...`aN`][argument values to a constructor of `T`]]
- [[`F`][the type `value_factory<F>`]]
- [[`f`][an instance object of `F`]]]
- [heading Expression Semantics]
- [table
- [[Expression][Semantics]]
- [[`F()`][creates an object of type `F`.]]
- [[`F(f)`][creates an object of type `F`.]]
- [[`f(a0`...`aN)`][returns `T(a0`...`aN)`.]]
- [[`F::result_type`][is the type `T`.]]]
- [heading Limits]
- Before C++11, the maximum number of arguments supported is 10. Since C++11 an
- arbitrary number of arguments is supported.
- [endsect]
- [section factory]
- [heading Description]
- Function object template that dynamically constructs a pointee object for the
- type of pointer given as template argument. Smart pointers may be used for the
- template argument, given that `pointer_traits<Pointer>::element_type` yields
- the pointee type.
- If an __allocator__ is given, it is used for memory allocation and the
- placement form of the `new` operator is used to construct the object. A
- function object that calls the destructor and deallocates the memory with a
- copy of the Allocator is used for the second constructor argument of `Pointer`
- (thus it must be a __smart_pointer__ that provides a suitable constructor,
- such as __boost__shared_ptr__).
- If a third template argument is `factory_passes_alloc_to_smart_pointer`, the
- allocator itself is used for the third constructor argument of `Pointer`
- (__boost__shared_ptr__ then uses the allocator to manage the memory of its
- separately allocated reference counter).
- [heading Header]
- ```
- #include <boost/functional/factory.hpp>
- ```
- [heading Synopsis]
- ```
- namespace boost {
- enum factory_alloc_propagation {
- factory_alloc_for_pointee_and_deleter,
- factory_passes_alloc_to_smart_pointer
- };
- template<class Pointer,
- class Allocator = void,
- factory_alloc_propagation Policy = factory_alloc_for_pointee_and_deleter>
- class factory;
- } // boost
- ```
- [variablelist Notation
- [[`T`][an arbitrary type with at least one public constructor]]
- [[`P`][pointer or smart pointer to `T`]]
- [[`a0`...`aN`][argument values to a constructor of `T`]]
- [[`F`][the type `factory<P>`]]
- [[`f`][an instance object of `F`]]]
- [heading Expression Semantics]
- [table
- [[Expression][Semantics]]
- [[`F()`][creates an object of type `F`.]]
- [[`F(f)`][creates an object of type `F`.]]
- [[`f(a0`...`aN)`]
- [dynamically creates an object of type `T` using `a0`...`aN` as arguments for
- the constructor invocation.]]
- [[`F::result_type`][is the type `P` with top-level cv-qualifiers removed.]]]
- [heading Limits]
- Before C++11, the maximum number of arguments supported is 10. Since C++11 an
- arbitrary number of arguments is supported.
- [endsect]
- [endsect]
- [section Changes]
- [heading Boost 1.72.0]
- Glen Fernandes rewrote the implementations of `factory` and `value_factory` to
- provide the following features:
- * Support r-value arguments when available
- * Support arbitrary number of arguments via variadic templates when available
- * Support allocators that are final
- * Support allocators that use fancy pointers
- * Support for disabled exceptions (`BOOST_NO_EXCEPTIONS`)
- * Improved compilation times
- The following features have been removed:
- * Increasing limits for C++03 compilers through
- `BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY`
- * Using `boost::none_t` in place of `void` through
- `BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T`
- [heading Boost 1.58.0]
- In order to remove the dependency on Boost.Optional, the default parameter for
- allocators has been changed from `boost::none_t` to `void`. If you have code
- that has stopped working because it uses `boost::none_t`, a quick fix is to
- define `BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T`, which will restore support,
- but this will be removed in a future release. It should be be relatively easy
- to fix this properly.
- [endsect]
- [section Acknowledgements]
- Tobias Schwinger for creating this library.
- Eric Niebler requested a function to invoke a type's constructor (with the
- arguments supplied as a Tuple) as a Fusion feature. These Factory utilities are
- a factored-out generalization of this idea.
- Dave Abrahams suggested Smart Pointer support for exception safety, providing
- useful hints for the implementation.
- Joel de Guzman's documentation style was copied from Fusion.
- Peter Dimov for sharing his insights on language details and their evolution.
- [endsect]
- [section References]
- # [@http://en.wikipedia.org/wiki/Design_Patterns Design Patterns],
- Gamma et al. - Addison Wesley Publishing, 1995
- # [@https://boost.org/sgi/stl/ Standard Template Library Programmer's Guide],
- Hewlett-Packard Company, 1994
- # [@http://www.boost.org/libs/bind/bind.html Boost.Bind],
- Peter Dimov, 2001-2005
- # [@http://www.boost.org/doc/html/function.html Boost.Function],
- Douglas Gregor, 2001-2004
- [endsect]
|