diff --git a/factory/doc/Jamfile b/factory/doc/Jamfile new file mode 100644 index 0000000..1653336 --- /dev/null +++ b/factory/doc/Jamfile @@ -0,0 +1,20 @@ + +# (C) Copyright Tobias Schwinger +# +# Use modification and distribution are subject to the boost Software License, +# Version 1.0. (See http:/\/www.boost.org/LICENSE_1_0.txt). + +using quickbook ; + +xml factory : factory.qbk ; +boostbook standalone : factory + : + boost.root=../../../../.. + boost.libraries=../../../../libraries.htm + chunk.section.depth=0 + chunk.first.sections=0 + generate.section.toc.level=2 + toc.max.depth=1 + ; + + diff --git a/factory/doc/factory.qbk b/factory/doc/factory.qbk new file mode 100644 index 0000000..487537c --- /dev/null +++ b/factory/doc/factory.qbk @@ -0,0 +1,384 @@ +[library Boost.Functional/Factory + [quickbook 1.3] + [version 1.0] + [authors [Schwinger, Tobias]] + [copyright 2007 2008 Tobias Schwinger] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] + [purpose Function object templates for object creation.] + [category higher-order] + [category generic] + [last-revision $Date: 2008/11/01 21:44:52 $] +] + +[def __boost_bind__ [@http://www.boost.org/libs/bind/bind.html Boost.Bind]] +[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 __fusion_functional_adapters__ [@http://www.boost.org/libs/fusion/doc/html/functional.html Fusion Functional Adapters]] + +[def __boost_function__ [@http://www.boost.org/doc/html/function.html Boost.Function]] +[def __boost__function__ [@http://www.boost.org/doc/html/function.html `boost::function`]] + +[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 __std__map__ [@http://www.sgi.com/tech/stl/map.html `std::map`]] +[def __std__string__ [@http://www.sgi.com/tech/stl/string.html `std::string`]] +[def __std_allocator__ [@http://www.sgi.com/tech/stl/concepts/allocator.html Allocator]] +[def __std_allocators__ [@http://www.sgi.com/tech/stl/concepts/allocator.html Allocators]] + +[def __boost__ptr_map__ [@http://www.boost.org/libs/ptr_container/doc/ptr_map.html `__boost__ptr_map__`]] + +[def __boost__factory__ `boost::factory`] +[def __boost__value_factory__ `boost::value_factory`] + +[def __factory__ `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__()(arg1,arg2,arg3) + // same as new T(arg1,arg2,arg3) + + __boost__value_factory__()(arg1,arg2,arg3) + // same as T(arg1,arg2,arg3) + +For technical reasons 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__. + +[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 + + class a_factory + { + public: + virtual an_abstract_class* create() const = 0; + virtual ~a_factory() { } + }; + + class a_concrete_factory : public a_factory + { + public: + virtual an_abstract_class* create() const + { + return new a_concrete_class(); + } + }; + + class another_concrete_factory : public a_factory + { + public: + virtual 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::auto_ptr( + new a_concrete_factory)); + factories.insert("another_name",std::auto_ptr( + new another_concrete_factory)); + + // [...] + + std::auto_ptr x = factories[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: + + o We may want a factory that takes some arguments that are forwarded to + the constructor, + o we will probably want to use smart pointers, + o we may want several member functions to create different kinds of + objects, + o we might not necessarily need a polymorphic base class for the objects, + o as we will see, we do not need a factory base class at all, + o we might want to just call the constructor - without `new` to create + an object on the stack, and + o 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 mechasisms +(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 encasulate +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. Overthis __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 inhomogenous signaturs 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__()); + do_something(boost::bind(__boost__value_factory__(),_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 + // 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 __factory__ instead + // of __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__(); + factories["another_name"] = + __boost__factory__(); + + // [...] + } + +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 + +[heading Synopsis] + + namespace boost + { + template< typename T > + class value_factory; + } + +[variablelist Notation + [[`T`] [an arbitrary type with at least one public constructor]] + [[`a0`...`aN`] [argument LValues to a constructor of `T`]] + [[`F`] [the type `value_factory`]] + [[`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] + +The macro BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY can be defined to set the +maximum arity. It defaults to 10. + +[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 `boost::pointee::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 +seperately allocated reference counter). + +[heading Header] + #include + +[heading Synopsis] + + namespace boost + { + enum factory_alloc_propagation + { + factory_alloc_for_pointee_and_deleter, + factory_passes_alloc_to_smart_pointer + }; + + template< typename Pointer, + class Allocator = boost::none_t, + factory_alloc_propagation AllocProp = + factory_alloc_for_pointee_and_deleter > + class factory; + } + +[variablelist Notation + [[`T`] [an arbitrary type with at least one public constructor]] + [[`P`] [pointer or smart pointer to `T`]] + [[`a0`...`aN`] [argument LValues to a constructor of `T`]] + [[`F`] [the type `factory

`]] + [[`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] + +The macro BOOST_FUNCTIONAL_FACTORY_MAX_ARITY can be defined to set the +maximum arity. It defaults to 10. + +[endsect] + +[endsect] + +[section Acknowledgements] + +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. + +Further, I want to thank 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 + +# [@http://www.sgi.com/tech/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] + + diff --git a/factory/doc/html/boostbook.css b/factory/doc/html/boostbook.css new file mode 100644 index 0000000..858d43c --- /dev/null +++ b/factory/doc/html/boostbook.css @@ -0,0 +1,528 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= + Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= + Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= + Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 90%; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= + Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font: 140% } + h2 { font: bold 140% } + h3 { font: bold 130% } + h4 { font: bold 120% } + h5 { font: italic 110% } + h6 { font: italic 100% } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 120% } + h5 tt.computeroutput { font-size: 110% } + h6 tt.computeroutput { font-size: 100% } + +/*============================================================================= + Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= + Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= + Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= + Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= + Table of contents +=============================================================================*/ + + .toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + +/*============================================================================= + Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + +/*============================================================================= + Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + div.sidebar + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.0pc 0.5pc; + } + + div.sidebar img + { + padding: 1pt; + } + +/*============================================================================= + Callouts +=============================================================================*/ + .line_callout_bug img + { + float: left; + position:relative; + left: 4px; + top: -12px; + clear: left; + margin-left:-22px; + } + + .callout_bug img + { + } + +/*============================================================================= + Variable Lists +=============================================================================*/ + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= + Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= + Colors +=============================================================================*/ + + @media screen + { + /* Links */ + a + { + color: #005a9c; + } + + a:visited + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + div.sidebar + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } diff --git a/factory/doc/html/index.html b/factory/doc/html/index.html new file mode 100644 index 0000000..93ce15f --- /dev/null +++ b/factory/doc/html/index.html @@ -0,0 +1,598 @@ + + + +Chapter 1. Boost.Functional/Factory 1.0 + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+


+
+
+
+

+Chapter 1. Boost.Functional/Factory 1.0

+

+Tobias Schwinger +

+
+
+

+ Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +

+
+
+ +
+ +

+ 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)
+
+

+ For technical reasons 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 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
+
+class a_factory
+{
+  public:
+    virtual an_abstract_class* create() const = 0;
+    virtual ~a_factory() { }
+};
+
+class a_concrete_factory : public a_factory
+{
+  public:
+    virtual an_abstract_class* create() const
+    {
+        return new a_concrete_class();
+    }
+};
+
+class another_concrete_factory : public a_factory
+{
+  public:
+    virtual 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::auto_ptr<a_factory>(
+        new a_concrete_factory));
+    factories.insert("another_name",std::auto_ptr<a_factory>(
+        new another_concrete_factory));
+
+    // [...]
+
+    std::auto_ptr<an_abstract_factory> x = factories[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: +

+
o We may want a factory that takes some arguments that are forwarded to
+  the constructor,
+o we will probably want to use smart pointers,
+o we may want several member functions to create different kinds of
+  objects,
+o we might not necessarily need a polymorphic base class for the objects,
+o as we will see, we do not need a factory base class at all, 
+o we might want to just call the constructor - without #new# to create
+  an object on the stack, and
+o 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 mechasisms (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 encasulate 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. Overthis boost::factory + optionally allows the use of smart pointers and 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 inhomogenous signaturs 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 __factory__ instead
+// of __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. +

+
+
+ + +
+ +

+ + Description +

+

+ Function object template that invokes the constructor of the type T. +

+

+ + Header +

+
#include <boost/functional/value_factory.hpp>
+
+

+ + Synopsis +

+
namespace boost
+{
+    template< typename T >
+    class value_factory;
+}
+
+
+

Notation

+
+
T
+

+ an arbitrary type with at least one public constructor +

+
a0...aN
+

+ argument LValues to a constructor of T +

+
F
+

+ the type value_factory<F> +

+
f
+

+ an instance object of F +

+
+
+

+ + Expression + Semantics +

+
++++ + + + + + + + + + + + + + + + + + + + + + + +
+

+ 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. +

+
+

+ + Limits +

+

+ The macro BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY can be defined to set + the maximum arity. It defaults to 10. +

+
+
+ +

+ + 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 boost::pointee<Pointer>::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 __smartpointer_ + 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 seperately allocated reference counter). +

+

+ + Header +

+
#include <boost/functional/factory.hpp>
+
+

+ + Synopsis +

+
namespace boost
+{
+    enum factory_alloc_propagation
+    {
+        factory_alloc_for_pointee_and_deleter,
+        factory_passes_alloc_to_smart_pointer
+    };
+
+    template< typename Pointer, 
+        class Allocator = boost::none_t,
+        factory_alloc_propagation AllocProp =
+            factory_alloc_for_pointee_and_deleter >
+    class factory;
+}
+
+
+

Notation

+
+
T
+

+ an arbitrary type with at least one public constructor +

+
P
+

+ pointer or smart pointer to T +

+
a0...aN
+

+ argument LValues to a constructor of T +

+
F
+

+ the type factory<P> +

+
f
+

+ an instance object of F +

+
+
+

+ + Expression + Semantics +

+
++++ + + + + + + + + + + + + + + + + + + + + + + +
+

+ 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. +

+
+

+ + Limits +

+

+ The macro BOOST_FUNCTIONAL_FACTORY_MAX_ARITY can be defined to set the maximum + arity. It defaults to 10. +

+
+
+
+ +

+ 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. +

+

+ Further, I want to thank Peter Dimov for sharing his insights on language details + and their evolution. +

+
+
+ +
    +
  1. +Design Patterns, + Gamma et al. - Addison Wesley Publishing, 1995 +
  2. +
  3. +Standard Template Library Programmer's + Guide, Hewlett-Packard Company, 1994 +
  4. +
  5. +Boost.Bind, + Peter Dimov, 2001-2005 +
  6. +
  7. +Boost.Function, + Douglas Gregor, 2001-2004 +
  8. +
+
+
+ + + +

Last revised: November 01, 2008 at 21:44:52 GMT

+
+
+ + diff --git a/factory/index.html b/factory/index.html new file mode 100644 index 0000000..1803029 --- /dev/null +++ b/factory/index.html @@ -0,0 +1,15 @@ + + + + + + + Automatic redirection failed, click this + link  
+

© Copyright Tobias Schwinger, 2009

+

Distributed under the Boost Software License, Version 1.0. (See + accompanying file + LICENSE_1_0.txt or copy at + www.boost.org/LICENSE_1_0.txt)

+ + diff --git a/factory/test/Jamfile b/factory/test/Jamfile new file mode 100644 index 0000000..6c4f6eb --- /dev/null +++ b/factory/test/Jamfile @@ -0,0 +1,18 @@ + +# (C) Copyright Tobias Schwinger +# +# Use modification and distribution are subject to the boost Software License, +# Version 1.0. (See http:/\/www.boost.org/LICENSE_1_0.txt). + +import testing ; + +project factory-tests + ; + +test-suite functional/factory + : + [ run value_factory.cpp ] + [ run factory.cpp ] + [ run factory_with_allocator.cpp ] + ; + diff --git a/factory/test/factory.cpp b/factory/test/factory.cpp new file mode 100644 index 0000000..dff40a7 --- /dev/null +++ b/factory/test/factory.cpp @@ -0,0 +1,36 @@ +/*============================================================================= + Copyright (c) 2007 Tobias Schwinger + + Use modification and distribution are subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +==============================================================================*/ + +#include +#include + +#include + +class sum +{ + int val_sum; + public: + sum(int a, int b) : val_sum(a + b) { } + + operator int() const { return this->val_sum; } +}; + +int main() +{ + int one = 1, two = 2; + { + sum* instance( boost::factory< sum* >()(one,two) ); + BOOST_TEST(*instance == 3); + } + { + std::auto_ptr instance( boost::factory< std::auto_ptr >()(one,two) ); + BOOST_TEST(*instance == 3); + } + return boost::report_errors(); +} + diff --git a/factory/test/factory_with_allocator.cpp b/factory/test/factory_with_allocator.cpp new file mode 100644 index 0000000..decd656 --- /dev/null +++ b/factory/test/factory_with_allocator.cpp @@ -0,0 +1,79 @@ +/*============================================================================= + Copyright (c) 2007 Tobias Schwinger + + Use modification and distribution are subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +==============================================================================*/ + +#include +#include + +#include +#include +#include + +using std::size_t; + +class sum +{ + int val_sum; + public: + sum(int a, int b) : val_sum(a + b) { } + + operator int() const { return this->val_sum; } +}; + +template< typename T > +class counting_allocator : public std::allocator +{ + public: + counting_allocator() + { } + + template< typename OtherT > + struct rebind { typedef counting_allocator other; }; + + template< typename OtherT > + counting_allocator(counting_allocator const& that) + { } + + static size_t n_allocated; + T* allocate(size_t n, void const* hint = 0l) + { + n_allocated += 1; + return std::allocator::allocate(n,hint); + } + + static size_t n_deallocated; + void deallocate(T* ptr, size_t n) + { + n_deallocated += 1; + return std::allocator::deallocate(ptr,n); + } +}; +template< typename T > size_t counting_allocator::n_allocated = 0; +template< typename T > size_t counting_allocator::n_deallocated = 0; + +int main() +{ + int one = 1, two = 2; + { + boost::shared_ptr instance( + boost::factory< boost::shared_ptr, counting_allocator, + boost::factory_alloc_for_pointee_and_deleter >()(one,two) ); + BOOST_TEST(*instance == 3); + } + BOOST_TEST(counting_allocator::n_allocated == 1); + BOOST_TEST(counting_allocator::n_deallocated == 1); + { + boost::shared_ptr instance( + boost::factory< boost::shared_ptr, counting_allocator, + boost::factory_passes_alloc_to_smart_pointer >()(one,two) ); + BOOST_TEST(*instance == 3); + } + BOOST_TEST(counting_allocator::n_allocated == 2); + BOOST_TEST(counting_allocator::n_deallocated == 2); + return boost::report_errors(); +} + diff --git a/factory/test/value_factory.cpp b/factory/test/value_factory.cpp new file mode 100644 index 0000000..e63c9ec --- /dev/null +++ b/factory/test/value_factory.cpp @@ -0,0 +1,29 @@ +/*============================================================================= + Copyright (c) 2007 Tobias Schwinger + + Use modification and distribution are subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +==============================================================================*/ + +#include +#include + +class sum +{ + int val_sum; + public: + sum(int a, int b) : val_sum(a + b) { } + operator int() const { return this->val_sum; } +}; + +int main() +{ + int one = 1, two = 2; + { + sum instance( boost::value_factory< sum >()(one,two) ); + BOOST_TEST(instance == 3); + } + return boost::report_errors(); +} + diff --git a/include/boost/functional/factory.hpp b/include/boost/functional/factory.hpp new file mode 100644 index 0000000..4aa4267 --- /dev/null +++ b/include/boost/functional/factory.hpp @@ -0,0 +1,163 @@ +/*============================================================================= + Copyright (c) 2007 Tobias Schwinger + + Use modification and distribution are subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +==============================================================================*/ + +#ifndef BOOST_FUNCTIONAL_FACTORY_HPP_INCLUDED +# ifndef BOOST_PP_IS_ITERATING + +# include +# include +# include + +# include +# include +# include +# include +# include +# include + +# ifndef BOOST_FUNCTIONAL_FACTORY_MAX_ARITY +# define BOOST_FUNCTIONAL_FACTORY_MAX_ARITY 10 +# elif BOOST_FUNCTIONAL_FACTORY_MAX_ARITY < 3 +# undef BOOST_FUNCTIONAL_FACTORY_MAX_ARITY +# define BOOST_FUNCTIONAL_FACTORY_MAX_ARITY 3 +# endif + +namespace boost +{ + enum factory_alloc_propagation + { + factory_alloc_for_pointee_and_deleter, + factory_passes_alloc_to_smart_pointer + }; + + template< typename Pointer, class Allocator = boost::none_t, + factory_alloc_propagation AP = factory_alloc_for_pointee_and_deleter > + class factory; + + //----- ---- --- -- - - - - + + template< typename Pointer, factory_alloc_propagation AP > + class factory + { + public: + typedef typename boost::remove_cv::type result_type; + typedef typename boost::pointee::type value_type; + + factory() + { } + +# define BOOST_PP_FILENAME_1 +# define BOOST_PP_ITERATION_LIMITS (0,BOOST_FUNCTIONAL_FACTORY_MAX_ARITY) +# include BOOST_PP_ITERATE() + }; + + template< class Pointer, class Allocator, factory_alloc_propagation AP > + class factory + : private Allocator::template rebind< typename boost::pointee< + typename boost::remove_cv::type >::type >::other + { + public: + typedef typename boost::remove_cv::type result_type; + typedef typename boost::pointee::type value_type; + + typedef typename Allocator::template rebind::other + allocator_type; + + explicit factory(allocator_type const & a = allocator_type()) + : allocator_type(a) + { } + + private: + + struct deleter + : allocator_type + { + inline deleter(allocator_type const& that) + : allocator_type(that) + { } + + allocator_type& get_allocator() const + { + return *const_cast( + static_cast(this)); + } + + void operator()(value_type* ptr) const + { + if (!! ptr) ptr->~value_type(); + const_cast(static_cast( + this))->deallocate(ptr,1); + } + }; + + inline allocator_type& get_allocator() const + { + return *const_cast( + static_cast(this)); + } + + inline result_type make_pointer(value_type* ptr, boost::non_type< + factory_alloc_propagation,factory_passes_alloc_to_smart_pointer>) + const + { + return result_type(ptr,deleter(this->get_allocator())); + } + inline result_type make_pointer(value_type* ptr, boost::non_type< + factory_alloc_propagation,factory_alloc_for_pointee_and_deleter>) + const + { + return result_type(ptr,deleter(this->get_allocator()), + this->get_allocator()); + } + + public: + +# define BOOST_TMP_MACRO +# define BOOST_PP_FILENAME_1 +# define BOOST_PP_ITERATION_LIMITS (0,BOOST_FUNCTIONAL_FACTORY_MAX_ARITY) +# include BOOST_PP_ITERATE() +# undef BOOST_TMP_MACRO + }; + + template< typename Pointer, class Allocator, factory_alloc_propagation AP > + class factory; + // forbidden, would create a dangling reference +} + +# define BOOST_FUNCTIONAL_FACTORY_HPP_INCLUDED +# else // defined(BOOST_PP_IS_ITERATING) +# define N BOOST_PP_ITERATION() +# if !defined(BOOST_TMP_MACRO) +# if N > 0 + template< BOOST_PP_ENUM_PARAMS(N, typename T) > +# endif + inline result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,& a)) const + { + return result_type( new value_type(BOOST_PP_ENUM_PARAMS(N,a)) ); + } +# else // defined(BOOST_TMP_MACRO) +# if N > 0 + template< BOOST_PP_ENUM_PARAMS(N, typename T) > +# endif + inline result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,& a)) const + { + value_type* memory = this->get_allocator().allocate(1); + try + { + return make_pointer( + new(memory) value_type(BOOST_PP_ENUM_PARAMS(N,a)), + boost::non_type() ); + } + catch (...) { this->get_allocator().deallocate(memory,1); throw; } + } +# endif +# undef N +# endif // defined(BOOST_PP_IS_ITERATING) + +#endif // include guard + diff --git a/include/boost/functional/value_factory.hpp b/include/boost/functional/value_factory.hpp new file mode 100644 index 0000000..6047908 --- /dev/null +++ b/include/boost/functional/value_factory.hpp @@ -0,0 +1,70 @@ +/*============================================================================= + Copyright (c) 2007 Tobias Schwinger + + Use modification and distribution are subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +==============================================================================*/ + +#ifndef BOOST_FUNCTIONAL_VALUE_FACTORY_HPP_INCLUDED +# ifndef BOOST_PP_IS_ITERATING + +# include +# include +# include + +# include +# include +# include +# include +# include +# include + +# ifndef BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY +# define BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY 10 +# elif BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY < 3 +# undef BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY +# define BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY 3 +# endif + +namespace boost +{ + template< typename T > + class value_factory; + + //----- ---- --- -- - - - - + + template< typename T > + class value_factory + { + public: + typedef T result_type; + + value_factory() + { } + +# define BOOST_PP_FILENAME_1 +# define BOOST_PP_ITERATION_LIMITS (0,BOOST_FUNCTIONAL_VALUE_FACTORY_MAX_ARITY) +# include BOOST_PP_ITERATE() + }; + + template< typename T > class value_factory; + // forbidden, would create a dangling reference +} +# define BOOST_FUNCTIONAL_VALUE_FACTORY_HPP_INCLUDED +# else // defined(BOOST_PP_IS_ITERATING) + +# define N BOOST_PP_ITERATION() +# if N > 0 + template< BOOST_PP_ENUM_PARAMS(N, typename T) > +# endif + inline result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,& a)) const + { + return result_type(BOOST_PP_ENUM_PARAMS(N,a)); + } +# undef N + +# endif // defined(BOOST_PP_IS_ITERATING) + +#endif // include guard +