433 lines
12 KiB
Plaintext
433 lines
12 KiB
Plaintext
[/
|
|
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]
|