From 0be6a0b06d4ee5a630e35a7d9711ce9462a773a4 Mon Sep 17 00:00:00 2001 From: Tobias Schwinger Date: Thu, 27 Nov 2008 15:15:47 +0000 Subject: [PATCH] introduces functional / factory & forward [SVN r49957] --- factory/doc/Jamfile | 20 + factory/doc/factory.qbk | 384 ++++++++++++ factory/doc/html/boostbook.css | 528 ++++++++++++++++ factory/doc/html/index.html | 598 +++++++++++++++++++ factory/test/Jamfile | 21 + factory/test/factory.cpp | 36 ++ factory/test/factory_with_allocator.cpp | 79 +++ factory/test/value_factory.cpp | 29 + forward/doc/Jamfile | 19 + forward/doc/forward.qbk | 316 ++++++++++ forward/doc/html/boostbook.css | 528 ++++++++++++++++ forward/doc/html/index.html | 564 +++++++++++++++++ forward/test/Jamfile | 20 + forward/test/forward_adapter.cpp | 127 ++++ forward/test/lightweight_forward_adapter.cpp | 128 ++++ 15 files changed, 3397 insertions(+) create mode 100644 factory/doc/Jamfile create mode 100644 factory/doc/factory.qbk create mode 100644 factory/doc/html/boostbook.css create mode 100644 factory/doc/html/index.html create mode 100644 factory/test/Jamfile create mode 100644 factory/test/factory.cpp create mode 100644 factory/test/factory_with_allocator.cpp create mode 100644 factory/test/value_factory.cpp create mode 100644 forward/doc/Jamfile create mode 100644 forward/doc/forward.qbk create mode 100644 forward/doc/html/boostbook.css create mode 100644 forward/doc/html/index.html create mode 100644 forward/test/Jamfile create mode 100644 forward/test/forward_adapter.cpp create mode 100644 forward/test/lightweight_forward_adapter.cpp 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/test/Jamfile b/factory/test/Jamfile new file mode 100644 index 0000000..4abdb68 --- /dev/null +++ b/factory/test/Jamfile @@ -0,0 +1,21 @@ + +# (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 + : requirements + /Users/tosh/Lab/boost + /Users/tosh/Lab/deploy/x_files/factory + ; + +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/forward/doc/Jamfile b/forward/doc/Jamfile new file mode 100644 index 0000000..5665497 --- /dev/null +++ b/forward/doc/Jamfile @@ -0,0 +1,19 @@ + +# (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 forward : forward.qbk ; +boostbook standalone : forward + : + 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/forward/doc/forward.qbk b/forward/doc/forward.qbk new file mode 100644 index 0000000..4eb227d --- /dev/null +++ b/forward/doc/forward.qbk @@ -0,0 +1,316 @@ +[library Boost.Functional/Forward + [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 adapters for generic argument forwarding.] + [category higher-order] + [category generic] + [last-revision $Date: 2008/11/01 19:58:50 $] +] + +[def __unspecified__ /unspecified/] +[def __boost_ref__ [@http://www.boost.org/doc/html/ref.html Boost.Ref]] +[def __boost_result_of__ [@http://www.boost.org/libs/utility/utility.htm#result_of Boost.ResultOf]] +[def __boost__result_of__ [@http://www.boost.org/libs/utility/utility.htm#result_of `boost::result_of`]] +[def __the_forwarding_problem__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm The Forwarding Problem]] +[def __boost_fusion__ [@http://www.boost.org/libs/fusion/doc/html/index.html Boost.Fusion]] + +[section Brief Description] + +`boost::forward_adapter` provides a reusable adapter template for function +objects. It forwards RValues as references to const, while leaving LValues +as-is. + + struct g // function object that only accept LValues + { + template< typename T0, typename T1, typename T2 > + void operator()(T0 & t0, T1 & t1, T2 & t2) const; + + typedef void result_type; + }; + + // Adapted version also accepts RValues and forwards + // them as references to const, LValues as-is + typedef boost::forward_adapter f; + +Another adapter, `boost::lighweight_forward_adapter` allows forwarding with +some help from the user accepting and unwrapping reference wrappers (see +__boost_ref__) for reference arguments, const qualifying all other arguments. + +The target functions must be compatible with __boost_result_of__, and so are +the adapters. + +[endsect] + +[section Background] + +Let's suppose we have some function `f` that we can call like this: + + f(123,a_variable); + +Now we want to write another, generic function `g` that can be called the +same way and returns some object that calls `f` with the same arguments. + + f(123,a_variable) == g(f,123,a_variable).call_f() + +[heading Why would we want to do it, anyway?] + +Maybe we want to run `f` several times. Or maybe we want to run it within +another thread. Maybe we just want to encapsulate the call expression for now, +and then use it with other code that allows to compose more complex expressions +in order to decompose it with C++ templates and have the compiler generate some +machinery that eventually calls `f` at runtime (in other words; apply a +technique that is commonly referred to as Expression Templates). + +[heading Now, how do we do it?] + +The bad news is: It's impossible. + +That is so because there is a slight difference between a variable and an +expression that evaluates to its value: Given + + int y; + int const z = 0; + +and + + template< typename T > void func1(T & x); + +we can call + + func1(y); // x is a reference to a non-const object + func1(z); // x is a reference to a const object + +where + + func1(1); // fails to compile. + +This way we can safely have `func1` store its reference argument and the +compiler keeps us from storing a reference to an object with temporary lifetime. + +It is important to realize that non-constness and whether an object binds to a +non-const reference parameter are two different properties. The latter is the +distinction between LValues and RValues. The names stem from the left hand side +and the right hand side of assignment expressions, thus LValues are typically +the ones you can assign to, and RValues the temporary results from the right +hand side expression. + + y = 1+2; // a is LValue, 1+2 is the expression producing the RValue, + // 1+2 = a; // usually makes no sense. + + func1(y); // works, because y is an LValue + // func1(1+2); // fails to compile, because we only got an RValue. + +If we add const qualification on the parameter, our function also accepts +RValues: + + template< typename T > void func2(T const & x); + + // [...] function scope: + func2(1); // x is a reference to a const temporary, object, + func2(y); // x is a reference to a const object, while y is not const, and + func2(z); // x is a reference to a const object, just like z. + +In all cases, the argument `x` in `func2` is a const-qualified LValue. +We can use function overloading to identify non-const LValues: + + template< typename T > void func3(T const & x); // #1 + template< typename T > void func3(T & x); // #2 + + // [...] function scope: + func3(1); // x is a reference to a const, temporary object in #1, + func3(y); // x is a reference to a non-const object in #2, and + func3(z); // x is a reference to a const object in #1. + +Note that all arguments `x` in the overloaded function `func3` are LValues. +In fact, there is no way to transport RValues into a function as-is in C++98. +Also note that we can't distinguish between what used to be a const qualified +LValue and an RValue. + +That's as close as we can get to a generic forwarding function `g` as +described above by the means of C++ 98. See __the_forwarding_problem__ for a +very detailed discussion including solutions that require language changes. + +Now, for actually implementing it, we need 2^N overloads for N parameters +(each with and without const qualifier) for each number of arguments +(that is 2^(Nmax+1) - 2^Nmin). Right, that means the compile-time complexity +is O(2^N), however the factor is low so it works quite well for a reasonable +number (< 10) of arguments. + +[endsect] + +[section:reference Reference] + +[section forward_adapter] + +[heading Description] + +Function object adapter template whose instances are callable with LValue and +RValue arguments. RValue arguments are forwarded as reference-to-const typed +LValues. + +An arity can be given as second, numeric non-type template argument to restrict +forwarding to a specific arity. +If a third, numeric non-type template argument is present, the second and third +template argument are treated as minimum and maximum arity, respectively. +Specifying an arity can be helpful to improve the readability of diagnostic +messages and compile time performance. + +__boost_result_of__ can be used to determine the result types of specific call +expressions. + +[heading Header] + #include + +[heading Synopsis] + + namespace boost + { + template< class Function, + int Arity_Or_MinArity = __unspecified__, int MaxArity = __unspecified__ > + class forward_adapter; + } + +[variablelist Notation + [[`F`] [a possibly const qualified function object type or reference type thereof]] + [[`f`] [an object convertible to `F`]] + [[`FA`] [the type `forward_adapter`]] + [[`fa`] [an instance object of `FA`, initialized with `f`]] + [[`a0`...`aN`] [arguments to `fa`]] +] + +The result type of a target function invocation must be + + __boost__result_of__::type + +where `TA0`...`TAN` denote the argument types of `a0`...`aN`. + +[heading Expression Semantics] + +[table + [[Expression] [Semantics]] + [[`FA(f)`] [creates an adapter, initializes the target function with `f`.]] + [[`FA()`] [creates an adapter, attempts to use `F`'s default constructor.]] + [[`fa(a0`...`aN)`] [calls `f` with with arguments `a0`...`aN`.]] +] + +[heading Limits] + +The macro BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY can be defined to set the +maximum call arity. It defaults to 6. + +[heading Complexity] + +Preprocessing time: O(2^N), where N is the arity limit. +Compile time: O(2^N), where N depends on the arity range. +Run time: O(0) if the compiler inlines, O(1) otherwise. + +[endsect] + + +[section lightweight_forward_adapter] + +[heading Description] + +Function object adapter template whose instances are callable with LValue and +RValue arguments. All arguments are forwarded as reference-to-const typed +LValues, except for reference wrappers which are unwrapped and may yield +non-const LValues. + +An arity can be given as second, numeric non-type template argument to restrict +forwarding to a specific arity. +If a third, numeric non-type template argument is present, the second and third +template argument are treated as minimum and maximum arity, respectively. +Specifying an arity can be helpful to improve the readability of diagnostic +messages and compile time performance. + +__boost_result_of__ can be used to determine the result types of specific call +expressions. + +[heading Header] + #include + +[heading Synopsis] + + namespace boost + { + template< class Function, + int Arity_Or_MinArity = __unspecified__, int MaxArity = __unspecified__ > + struct lightweight_forward_adapter; + } + +[variablelist Notation + [[`F`] [a possibly const qualified function object type or reference type thereof]] + [[`f`] [an object convertible to `F`]] + [[`FA`] [the type `lightweight_forward_adapter`]] + [[`fa`] [an instance of `FA`, initialized with `f`]] + [[`a0`...`aN`] [arguments to `fa`]] +] + +The result type of a target function invocation must be + + __boost__result_of__::type + +where `TA0`...`TAN` denote the argument types of `a0`...`aN`. + +[heading Expression Semantics] + +[table + [[Expression] [Semantics]] + [[`FA(f)`] [creates an adapter, initializes the target function with `f`.]] + [[`FA()`] [creates an adapter, attempts to use `F`'s default constructor.]] + [[`fa(a0`...`aN)`] [calls `f` with with const arguments `a0`...`aN`. If `aI` is a + reference wrapper it is unwrapped.]] +] + +[heading Limits] + +The macro BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY can be defined +to set the maximum call arity. It defaults to 10. + +[heading Complexity] + +Preprocessing time: O(N), where N is the arity limit. +Compile time: O(N), where N is the effective arity of a call. +Run time: O(0) if the compiler inlines, O(1) otherwise. + +[endsect] + +[endsect] + + +[section Acknowledgements] + +As these utilities are factored out of the __boost_fusion__ functional module, +I want to thank Dan Marsden and Joel de Guzman for letting me participate in the +development of that great library in the first place. + +Further, I want to credit the authors of the references below, for their +in-depth investigation of the problem and the solution implemented here. + +Last but not least I want to thank Vesa Karnoven and Paul Mensonides for the +Boost Preprocessor library. Without it, I would have ended up with an external +code generator for this one. + +[endsect] + + +[section References] + +# [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm The Forwarding Problem], + Peter Dimov, Howard E. Hinnant, David Abrahams, 2002 + +# [@http://www.boost.org/libs/utility/utility.htm#result_of Boost.ResultOf], + Douglas Gregor, 2004 + +# [@http://www.boost.org/doc/html/ref.html Boost.Ref], + Jaakko Jarvi, Peter Dimov, Douglas Gregor, David Abrahams, 1999-2002 + +[endsect] + diff --git a/forward/doc/html/boostbook.css b/forward/doc/html/boostbook.css new file mode 100644 index 0000000..858d43c --- /dev/null +++ b/forward/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/forward/doc/html/index.html b/forward/doc/html/index.html new file mode 100644 index 0000000..e82fe81 --- /dev/null +++ b/forward/doc/html/index.html @@ -0,0 +1,564 @@ + + + +Chapter 1. Boost.Functional/Forward 1.0 + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+
+
+

+Chapter 1. Boost.Functional/Forward 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) +

+
+
+ +
+ +

+ boost::forward_adapter provides a reusable adapter + template for function objects. It forwards RValues as references to const, + while leaving LValues as-is. +

+
struct g // function object that only accept LValues
+{
+    template< typename T0, typename T1, typename T2 >
+    void operator()(T0 & t0, T1 & t1, T2 & t2) const;
+
+    typedef void result_type;
+};
+
+// Adapted version also accepts RValues and forwards
+// them as references to const, LValues as-is
+typedef boost::forward_adapter<g> f;
+
+

+ Another adapter, boost::lighweight_forward_adapter allows forwarding + with some help from the user accepting and unwrapping reference wrappers (see + Boost.Ref) for + reference arguments, const qualifying all other arguments. +

+

+ The target functions must be compatible with Boost.ResultOf, + and so are the adapters. +

+
+
+ +

+ Let's suppose we have some function f + that we can call like this: +

+
f(123,a_variable);
+
+

+ Now we want to write another, generic function g + that can be called the same way and returns some object that calls f with the same arguments. +

+
f(123,a_variable) == g(f,123,a_variable).call_f()
+
+

+ + Why + would we want to do it, anyway? +

+

+ Maybe we want to run f several + times. Or maybe we want to run it within another thread. Maybe we just want + to encapsulate the call expression for now, and then use it with other code + that allows to compose more complex expressions in order to decompose it with + C++ templates and have the compiler generate some machinery that eventually + calls f at runtime (in other + words; apply a technique that is commonly referred to as Expression Templates). +

+

+ + Now, + how do we do it? +

+

+ The bad news is: It's impossible. +

+

+ That is so because there is a slight difference between a variable and an expression + that evaluates to its value: Given +

+
int y;
+int const z = 0;
+
+

+ and +

+
template< typename T > void func1(T & x);
+
+

+ we can call +

+
func1(y); // x is a reference to a non-const object
+func1(z); // x is a reference to a const object
+
+

+ where +

+
func1(1); // fails to compile.
+
+

+ This way we can safely have func1 + store its reference argument and the compiler keeps us from storing a reference + to an object with temporary lifetime. +

+

+ It is important to realize that non-constness and whether an object binds to + a non-const reference parameter are two different properties. The latter is + the distinction between LValues and RValues. The names stem from the left hand + side and the right hand side of assignment expressions, thus LValues are typically + the ones you can assign to, and RValues the temporary results from the right + hand side expression. +

+
y = 1+2;        // a is LValue, 1+2 is the expression producing the RValue,
+// 1+2 = a;     // usually makes no sense. 
+
+func1(y);       // works, because y is an LValue
+// func1(1+2);  // fails to compile, because we only got an RValue.
+
+

+ If we add const qualification on the parameter, our function also accepts RValues: +

+
template< typename T > void func2(T const & x);
+
+// [...] function scope:
+func2(1); // x is a reference to a const temporary, object,
+func2(y); // x is a reference to a const object, while y is not const, and
+func2(z); // x is a reference to a const object, just like z.
+
+

+ In all cases, the argument x + in func2 is a const-qualified + LValue. We can use function overloading to identify non-const LValues: +

+
template< typename T > void func3(T const & x); // #1
+template< typename T > void func3(T & x);       // #2
+
+// [...] function scope:
+func3(1); // x is a reference to a const, temporary object in #1,
+func3(y); // x is a reference to a non-const object in #2, and
+func3(z); // x is a reference to a const object in #1.
+
+

+ Note that all arguments x in + the overloaded function func3 + are LValues. In fact, there is no way to transport RValues into a function + as-is in C++98. Also note that we can't distinguish between what used to be + a const qualified LValue and an RValue. +

+

+ That's as close as we can get to a generic forwarding function g as described above by the means of C++ + 98. See The + Forwarding Problem for a very detailed discussion including solutions + that require language changes. +

+

+ Now, for actually implementing it, we need 2^N overloads for N parameters (each + with and without const qualifier) for each number of arguments (that is 2^(Nmax+1) + - 2^Nmin). Right, that means the compile-time complexity is O(2^N), however + the factor is low so it works quite well for a reasonable number (< 10) + of arguments. +

+
+
+ + +
+ +

+ + Description +

+

+ Function object adapter template whose instances are callable with LValue + and RValue arguments. RValue arguments are forwarded as reference-to-const + typed LValues. +

+

+ An arity can be given as second, numeric non-type template argument to restrict + forwarding to a specific arity. If a third, numeric non-type template argument + is present, the second and third template argument are treated as minimum + and maximum arity, respectively. Specifying an arity can be helpful to improve + the readability of diagnostic messages and compile time performance. +

+

+ Boost.ResultOf + can be used to determine the result types of specific call expressions. +

+

+ + Header +

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

+ + Synopsis +

+
namespace boost
+{
+    template< class Function,
+        int Arity_Or_MinArity = unspecified, int MaxArity = unspecified >
+    class forward_adapter;
+}
+
+
+

Notation

+
+
F
+

+ a possibly const qualified function object type or reference type thereof +

+
f
+

+ an object convertible to F +

+
FA
+

+ the type forward_adapter<F> +

+
fa
+

+ an instance object of FA, + initialized with f +

+
a0...aN
+

+ arguments to fa +

+
+
+

+ The result type of a target function invocation must be +

+
boost::result_of<F*(TA0 [const]&...TAN [const]&])>::type
+
+

+ where TA0...TAN denote the argument types of a0...aN. +

+

+ + Expression + Semantics +

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

+ Expression +

+
+

+ Semantics +

+
+

+ FA(f) +

+
+

+ creates an adapter, initializes the target function with f. +

+
+

+ FA() +

+
+

+ creates an adapter, attempts to use F's + default constructor. +

+
+

+ fa(a0...aN) +

+
+

+ calls f with with + arguments a0...aN. +

+
+

+ + Limits +

+

+ The macro BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY can be defined to set + the maximum call arity. It defaults to 6. +

+

+ + Complexity +

+

+ Preprocessing time: O(2^N), where N is the arity limit. Compile time: O(2^N), + where N depends on the arity range. Run time: O(0) if the compiler inlines, + O(1) otherwise. +

+
+
+ +

+ + Description +

+

+ Function object adapter template whose instances are callable with LValue + and RValue arguments. All arguments are forwarded as reference-to-const typed + LValues, except for reference wrappers which are unwrapped and may yield + non-const LValues. +

+

+ An arity can be given as second, numeric non-type template argument to restrict + forwarding to a specific arity. If a third, numeric non-type template argument + is present, the second and third template argument are treated as minimum + and maximum arity, respectively. Specifying an arity can be helpful to improve + the readability of diagnostic messages and compile time performance. +

+

+ Boost.ResultOf + can be used to determine the result types of specific call expressions. +

+

+ + Header +

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

+ + Synopsis +

+
namespace boost
+{
+    template< class Function,
+        int Arity_Or_MinArity = unspecified, int MaxArity = unspecified >
+    struct lightweight_forward_adapter;
+}
+
+
+

Notation

+
+
F
+

+ a possibly const qualified function object type or reference type thereof +

+
f
+

+ an object convertible to F +

+
FA
+

+ the type lightweight_forward_adapter<F> +

+
fa
+

+ an instance of FA, initialized + with f +

+
a0...aN
+

+ arguments to fa +

+
+
+

+ The result type of a target function invocation must be +

+
boost::result_of<F*(TA0 [const]&...TAN [const]&])>::type
+
+

+ where TA0...TAN denote the argument types of a0...aN. +

+

+ + Expression + Semantics +

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

+ Expression +

+
+

+ Semantics +

+
+

+ FA(f) +

+
+

+ creates an adapter, initializes the target function with f. +

+
+

+ FA() +

+
+

+ creates an adapter, attempts to use F's + default constructor. +

+
+

+ fa(a0...aN) +

+
+

+ calls f with with + const arguments a0...aN. If aI + is a reference wrapper it is unwrapped. +

+
+

+ + Limits +

+

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

+

+ + Complexity +

+

+ Preprocessing time: O(N), where N is the arity limit. Compile time: O(N), + where N is the effective arity of a call. Run time: O(0) if the compiler + inlines, O(1) otherwise. +

+
+
+
+ +

+ As these utilities are factored out of the Boost.Fusion + functional module, I want to thank Dan Marsden and Joel de Guzman for letting + me participate in the development of that great library in the first place. +

+

+ Further, I want to credit the authors of the references below, for their in-depth + investigation of the problem and the solution implemented here. +

+

+ Last but not least I want to thank Vesa Karnoven and Paul Mensonides for the + Boost Preprocessor library. Without it, I would have ended up with an external + code generator for this one. +

+
+
+ +
    +
  1. +The + Forwarding Problem, Peter Dimov, Howard E. Hinnant, David Abrahams, + 2002 +
  2. +
  3. +Boost.ResultOf, + Douglas Gregor, 2004 +
  4. +
  5. +Boost.Ref, Jaakko + Jarvi, Peter Dimov, Douglas Gregor, David Abrahams, 1999-2002 +
  6. +
+
+
+ + + +

Last revised: November 01, 2008 at 19:58:50 GMT

+
+
+ + diff --git a/forward/test/Jamfile b/forward/test/Jamfile new file mode 100644 index 0000000..56c01d3 --- /dev/null +++ b/forward/test/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). + +import testing ; + +project forward-tests + : requirements + /Users/tosh/Lab/boost + /Users/tosh/Lab/deploy/x_files/forward + ; + +test-suite functional/forward + : + [ run forward_adapter.cpp ] + [ run lightweight_forward_adapter.cpp ] + ; + diff --git a/forward/test/forward_adapter.cpp b/forward/test/forward_adapter.cpp new file mode 100644 index 0000000..6956d4e --- /dev/null +++ b/forward/test/forward_adapter.cpp @@ -0,0 +1,127 @@ +/*============================================================================= + 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 + +#ifdef BOOST_MSVC +# pragma warning(disable: 4244) // no conversion warnings, please +#endif + +#include +#include + +#include + +#include +#include + +#include + +template +class test_func : public Base +{ + int val; +public: + test_func(int v) : val(v) { } + + template + test_func(test_func const & that) + : val(that.val) + { } + + template friend class test_func; + + int operator()(int & l, int const & r) const + { + return l=r+val; + } + long operator()(int & l, int const & r) + { + return -(l=r+val); + } + + template + struct result + { + typedef void type; + }; + + // ensure result_of argument types are what's expected + // note: this is *not* how client code should look like + template + struct result< Self const(int&,int const&) > { typedef int type; }; + + template + struct result< Self(int&,int const&) > { typedef long type; }; + + template + struct result< Self(int&,int&) > { typedef char type; }; +}; + +enum { int_, long_, char_ }; + +int type_of(int) { return int_; } +int type_of(long) { return long_; } +int type_of(char) { return char_; } + +int main() +{ + { + using boost::is_same; + using boost::result_of; + typedef boost::forward_adapter< test_func<> > f; + + // lvalue,rvalue + BOOST_TEST(( is_same< + result_of< f(int&, int) >::type, long >::value )); + BOOST_TEST(( is_same< + result_of< f const (int&, int) >::type, int >::value )); + // lvalue,const lvalue + BOOST_TEST(( is_same< + result_of< f(int&, int const &) >::type, long >::value )); + BOOST_TEST(( is_same< + result_of< f const (int&, int const &) >::type, int >::value )); + // lvalue,lvalue + BOOST_TEST(( is_same< + result_of< f(int&, int&) >::type, char >::value )); + BOOST_TEST(( is_same< + result_of< f const (int&, int&) >::type, char >::value )); + } + { + using boost::noncopyable; + using boost::forward_adapter; + + int x = 0; + test_func f(7); + forward_adapter< test_func<> > func(f); + forward_adapter< test_func & > func_ref(f); + forward_adapter< test_func & > const func_ref_c(f); + forward_adapter< test_func<> const > func_c(f); + forward_adapter< test_func<> > const func_c2(f); + forward_adapter< test_func const & > func_c_ref(f); + + BOOST_TEST( type_of( func(x,1) ) == long_ ); + BOOST_TEST( type_of( func_ref(x,1) ) == long_ ); + BOOST_TEST( type_of( func_ref_c(x,1) ) == long_ ); + BOOST_TEST( type_of( func_c(x,1) ) == int_ ); + BOOST_TEST( type_of( func_c2(x,1) ) == int_ ); + BOOST_TEST( type_of( func_c_ref(x,1) ) == int_ ); + BOOST_TEST( type_of( func(x,x) ) == char_ ); + + BOOST_TEST( func(x,1) == -8 ); + BOOST_TEST( func_ref(x,1) == -8 ); + BOOST_TEST( func_ref_c(x,1) == -8 ); + BOOST_TEST( func_c(x,1) == 8 ); + BOOST_TEST( func_c2(x,1) == 8 ); + BOOST_TEST( func_c_ref(x,1) == 8 ); + } + + return boost::report_errors(); +} + + diff --git a/forward/test/lightweight_forward_adapter.cpp b/forward/test/lightweight_forward_adapter.cpp new file mode 100644 index 0000000..7b0d304 --- /dev/null +++ b/forward/test/lightweight_forward_adapter.cpp @@ -0,0 +1,128 @@ +/*============================================================================= + 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 + +#ifdef BOOST_MSVC +# pragma warning(disable: 4244) // no conversion warnings, please +#endif + +#include +#include + +#include + +#include +#include + +#include + +template +class test_func : public Base +{ + int val; +public: + test_func(int v) : val(v) { } + + template + test_func(test_func const & that) + : val(that.val) + { } + + template friend class test_func; + + int operator()(int & l, int const & r) const + { + return l=r+val; + } + long operator()(int & l, int const & r) + { + return -(l=r+val); + } + + template + struct result + { + typedef void type; + }; + + // ensure result_of argument types are what's expected + // note: this is *not* how client code should look like + template + struct result< Self const(int&,int const&) > { typedef int type; }; + + template + struct result< Self(int&,int const&) > { typedef long type; }; + + template + struct result< Self(int&,int&) > { typedef char type; }; +}; + +enum { int_, long_, char_ }; + +int type_of(int) { return int_; } +int type_of(long) { return long_; } +int type_of(char) { return char_; } + +int main() +{ + { + using boost::is_same; + using boost::result_of; + typedef boost::lightweight_forward_adapter< test_func<> > f; + typedef boost::reference_wrapper ref; + typedef boost::reference_wrapper cref; + + // lvalue,rvalue + BOOST_TEST(( is_same< + result_of< f(ref, int) >::type, long >::value )); + BOOST_TEST(( is_same< + result_of< f const (ref, int) >::type, int >::value )); + // lvalue,const lvalue + BOOST_TEST(( is_same< + result_of< f(ref, cref) >::type, long >::value )); + BOOST_TEST(( is_same< + result_of< f const (ref, cref) >::type, int >::value )); + // lvalue,lvalue + BOOST_TEST(( is_same< + result_of< f(ref, ref) >::type, char >::value )); + BOOST_TEST(( is_same< + result_of< f const (ref, ref) >::type, char >::value )); + } + { + using boost::noncopyable; + using boost::lightweight_forward_adapter; + + int v = 0; boost::reference_wrapper x(v); + test_func f(7); + lightweight_forward_adapter< test_func<> > func(f); + lightweight_forward_adapter< test_func & > func_ref(f); + lightweight_forward_adapter< test_func & > const func_ref_c(f); + lightweight_forward_adapter< test_func<> const > func_c(f); + lightweight_forward_adapter< test_func<> > const func_c2(f); + lightweight_forward_adapter< test_func const & > func_c_ref(f); + + BOOST_TEST( type_of( func(x,1) ) == long_ ); + BOOST_TEST( type_of( func_ref(x,1) ) == long_ ); + BOOST_TEST( type_of( func_ref_c(x,1) ) == long_ ); + BOOST_TEST( type_of( func_c(x,1) ) == int_ ); + BOOST_TEST( type_of( func_c2(x,1) ) == int_ ); + BOOST_TEST( type_of( func_c_ref(x,1) ) == int_ ); + BOOST_TEST( type_of( func(x,x) ) == char_ ); + + BOOST_TEST( func(x,1) == -8 ); + BOOST_TEST( func_ref(x,1) == -8 ); + BOOST_TEST( func_ref_c(x,1) == -8 ); + BOOST_TEST( func_c(x,1) == 8 ); + BOOST_TEST( func_c2(x,1) == 8 ); + BOOST_TEST( func_c_ref(x,1) == 8 ); + } + + return boost::report_errors(); +} +