From 3cec009503b09f14dc86dd7fe2577d02f4566b2a Mon Sep 17 00:00:00 2001 From: Tobias Schwinger Date: Mon, 26 Apr 2010 23:21:31 +0000 Subject: [PATCH] adds Functional/Forward [SVN r61597] --- forward/doc/Jamfile | 19 + forward/doc/forward.qbk | 316 ++++++++++ forward/doc/html/boostbook.css | 528 ++++++++++++++++ forward/doc/html/index.html | 564 ++++++++++++++++++ forward/index.html | 15 + forward/test/Jamfile | 17 + forward/test/forward_adapter.cpp | 128 ++++ forward/test/lightweight_forward_adapter.cpp | 128 ++++ include/boost/functional/forward_adapter.hpp | 472 +++++++++++++++ .../lightweight_forward_adapter.hpp | 259 ++++++++ 10 files changed, 2446 insertions(+) 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/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 create mode 100644 include/boost/functional/forward_adapter.hpp create mode 100644 include/boost/functional/lightweight_forward_adapter.hpp 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/index.html b/forward/index.html new file mode 100644 index 0000000..1803029 --- /dev/null +++ b/forward/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/forward/test/Jamfile b/forward/test/Jamfile new file mode 100644 index 0000000..9169456 --- /dev/null +++ b/forward/test/Jamfile @@ -0,0 +1,17 @@ + +# (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 + ; + +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..2317ce7 --- /dev/null +++ b/forward/test/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::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(); +} + diff --git a/include/boost/functional/forward_adapter.hpp b/include/boost/functional/forward_adapter.hpp new file mode 100644 index 0000000..c6e61a9 --- /dev/null +++ b/include/boost/functional/forward_adapter.hpp @@ -0,0 +1,472 @@ +/*============================================================================= + Copyright (c) 2007-2008 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_FORWARD_ADAPTER_HPP_INCLUDED +# ifndef BOOST_PP_IS_ITERATING + +# include +# include + +# include +# include +# include +# include +# include + +# include + +# ifndef BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY +# define BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY 6 +# elif BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY < 3 +# undef BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY +# define BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY 3 +# endif + + +namespace boost +{ + template< typename Function, int Arity_Or_MinArity = -1, int MaxArity = -1 > + class forward_adapter; + + //----- ---- --- -- - - - - + + namespace detail + { + template< class MostDerived, typename Function, typename FunctionConst, + int Arity, int MinArity > + struct forward_adapter_impl; + + struct forward_adapter_result + { + template< typename Sig > struct apply; + + // Utility metafunction for qualification adjustment on arguments + template< typename T > struct q { typedef T const t; }; + template< typename T > struct q { typedef T const t; }; + template< typename T > struct q { typedef T t; }; + + // Utility metafunction to choose target function qualification + template< typename T > struct c + { typedef typename T::target_function_t t; }; + template< typename T > struct c + { typedef typename T::target_function_t t; }; + template< typename T > struct c + { typedef typename T::target_function_const_t t; }; + template< typename T > struct c + { typedef typename T::target_function_const_t t; }; + }; + } + +# define BOOST_TMP_MACRO(f,fn,fc) \ + boost::detail::forward_adapter_impl< \ + forward_adapter, fn, fc, \ + (MaxArity!=-1? MaxArity :Arity_Or_MinArity!=-1? Arity_Or_MinArity \ + :BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY), \ + (Arity_Or_MinArity!=-1? Arity_Or_MinArity : 0) > + + template< typename Function, int Arity_Or_MinArity, int MaxArity > + class forward_adapter + : public BOOST_TMP_MACRO(Function,Function,Function const) + , private Function + { + public: + forward_adapter(Function const& f = Function()) + : Function(f) + { } + + typedef Function target_function_t; + typedef Function const target_function_const_t; + + Function & target_function() { return *this; } + Function const & target_function() const { return *this; } + + template< typename Sig > struct result + : detail::forward_adapter_result::template apply + { }; + + using BOOST_TMP_MACRO(Function,Function, Function const)::operator(); + }; + template< typename Function, int Arity_Or_MinArity, int MaxArity > + class forward_adapter< Function const, Arity_Or_MinArity, MaxArity > + : public BOOST_TMP_MACRO(Function const, Function const, Function const) + , private Function + { + public: + forward_adapter(Function const& f = Function()) + : Function(f) + { } + + typedef Function const target_function_t; + typedef Function const target_function_const_t; + + Function const & target_function() const { return *this; } + + template< typename Sig > struct result + : detail::forward_adapter_result::template apply + { }; + + using BOOST_TMP_MACRO(Function const,Function const, Function const) + ::operator(); + }; + template< typename Function, int Arity_Or_MinArity, int MaxArity > + class forward_adapter< Function &, Arity_Or_MinArity, MaxArity > + : public BOOST_TMP_MACRO(Function&, Function, Function) + { + Function& ref_function; + public: + forward_adapter(Function& f) + : ref_function(f) + { } + + typedef Function target_function_t; + typedef Function target_function_const_t; + + Function & target_function() const { return this->ref_function; } + + template< typename Sig > struct result + : detail::forward_adapter_result::template apply + { }; + + using BOOST_TMP_MACRO(Function&, Function, Function)::operator(); + }; + + #undef BOOST_TMP_MACRO + + namespace detail + { + template< class Self > + struct forward_adapter_result::apply< Self() > + : boost::result_of< typename c::t() > + { }; + + template< class MD, class F, class FC > + struct forward_adapter_impl + { + inline typename boost::result_of< FC() >::type + operator()() const + { + return static_cast(this)->target_function()(); + } + + inline typename boost::result_of< F() >::type + operator()() + { + return static_cast(this)->target_function()(); + } + + // closing brace gets generated by preprocessing code, below + +# define BOOST_TMP_MACRO(tpl_params,arg_types,params,args) \ + template< tpl_params > \ + inline typename boost::result_of< FC(arg_types) >::type \ + operator()(params) const \ + { \ + return static_cast(this)->target_function()(args); \ + } \ + template< tpl_params > \ + inline typename boost::result_of< F(arg_types)>::type \ + operator()(params) \ + { \ + return static_cast(this)->target_function()(args); \ + } + +# // This is the total number of iterations we need +# define count ((1 << BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY+1)-2) + +# // Chain file iteration to virtually one loop +# if BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY <= 7 +# define limit1 count +# define limit2 0 +# define limit3 0 +# else +# if BOOST_FUNCTIONAL_FORWARD_ADAPTER_MAX_ARITY <= 15 +# define limit1 (count >> 8) +# define limit2 255 +# define limit3 0 +# else +# define limit1 (count >> 16) +# define limit2 255 +# define limit3 255 +# endif +# endif + +# define N 0 + +# define BOOST_PP_FILENAME_1 +# define BOOST_PP_ITERATION_LIMITS (0,limit1) +# include BOOST_PP_ITERATE() + +# undef N +# undef limit3 +# undef limit2 +# undef limit1 +# undef count +# undef BOOST_TMP_MACRO + + }; + + } // namespace detail + + template + struct result_of const ()> + : boost::detail::forward_adapter_result::template apply< + boost::forward_adapter const () > + { }; + template + struct result_of()> + : boost::detail::forward_adapter_result::template apply< + boost::forward_adapter() > + { }; + template + struct result_of const& ()> + : boost::detail::forward_adapter_result::template apply< + boost::forward_adapter const () > + { }; + template + struct result_of& ()> + : boost::detail::forward_adapter_result::template apply< + boost::forward_adapter() > + { }; +} + +# define BOOST_FUNCTIONAL_FORWARD_ADAPTER_HPP_INCLUDED + +# elif BOOST_PP_ITERATION_DEPTH() == 1 && limit2 +# define BOOST_PP_FILENAME_2 +# define BOOST_PP_ITERATION_LIMITS (0,limit2) +# include BOOST_PP_ITERATE() +# elif BOOST_PP_ITERATION_DEPTH() == 2 && limit3 +# define BOOST_PP_FILENAME_3 +# define BOOST_PP_ITERATION_LIMITS (0,limit3) +# include BOOST_PP_ITERATE() + +# else + +# // I is the loop counter +# if limit2 && limit3 +# define I (BOOST_PP_ITERATION_1 << 16 | BOOST_PP_ITERATION_2 << 8 | \ + BOOST_PP_ITERATION_3) +# elif limit2 +# define I (BOOST_PP_ITERATION_1 << 8 | BOOST_PP_ITERATION_2) +# else +# define I BOOST_PP_ITERATION_1 +# endif + +# if I < count + +# // Done for this arity? Increment N +# if (I+2 >> N+1) +# if N == 0 +# undef N +# define N 1 +# elif N == 1 +# undef N +# define N 2 +# elif N == 2 +# undef N +# define N 3 +# elif N == 3 +# undef N +# define N 4 +# elif N == 4 +# undef N +# define N 5 +# elif N == 5 +# undef N +# define N 6 +# elif N == 6 +# undef N +# define N 7 +# elif N == 7 +# undef N +# define N 8 +# elif N == 8 +# undef N +# define N 9 +# elif N == 9 +# undef N +# define N 10 +# elif N == 10 +# undef N +# define N 11 +# elif N == 11 +# undef N +# define N 12 +# elif N == 12 +# undef N +# define N 13 +# elif N == 13 +# undef N +# define N 14 +# elif N == 14 +# undef N +# define N 15 +# elif N == 15 +# undef N +# define N 16 +# endif + + }; + + template< class Self, BOOST_PP_ENUM_PARAMS(N,typename T) > + struct forward_adapter_result::apply< Self(BOOST_PP_ENUM_PARAMS(N,T)) > + : boost::result_of< + typename c::t(BOOST_PP_ENUM_BINARY_PARAMS(N, + typename q::t& BOOST_PP_INTERCEPT)) > + { }; + + template< class MD, class F, class FC > + struct forward_adapter_impl + { + template< BOOST_PP_ENUM_PARAMS(N,typename T) > + inline typename boost::result_of< F( + BOOST_PP_ENUM_BINARY_PARAMS(N,T,& BOOST_PP_INTERCEPT)) >::type + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,& BOOST_PP_INTERCEPT)); + }; + + template< class MD, class F, class FC, int MinArity > + struct forward_adapter_impl + : forward_adapter_impl + { + using forward_adapter_impl::operator(); + +# endif + +# // Zero based count for each arity would be I-(1< + inline typename boost::result_of< FC(BOOST_PP_ENUM_PARAMS(N,PT)) + >::type + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,PT,a)) const + { + return static_cast(this) + ->target_function()(BOOST_PP_ENUM_PARAMS(N,a)); + } + template< BOOST_PP_ENUM_PARAMS(N,typename T) > + inline typename boost::result_of< F(BOOST_PP_ENUM_PARAMS(N,PT)) + >::type + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,PT,a)) + { + return static_cast(this) + ->target_function()(BOOST_PP_ENUM_PARAMS(N,a)); + } +# else + BOOST_TMP_MACRO(BOOST_PP_ENUM_PARAMS(N,typename T), + BOOST_PP_ENUM_PARAMS(N,PT), BOOST_PP_ENUM_BINARY_PARAMS(N,PT,a), + BOOST_PP_ENUM_PARAMS(N,a) ) + // ...generates uglier code but is faster - it caches ENUM_* +# endif + +# undef PT0 +# undef PT1 +# undef PT2 +# undef PT3 +# undef PT4 +# undef PT5 +# undef PT6 +# undef PT7 +# undef PT8 +# undef PT9 +# undef PT10 +# undef PT11 +# undef PT12 +# undef PT13 +# undef PT14 +# undef PT15 + +# endif // I < count + +# undef I +# endif // defined(BOOST_PP_IS_ITERATING) + +#endif // include guard + diff --git a/include/boost/functional/lightweight_forward_adapter.hpp b/include/boost/functional/lightweight_forward_adapter.hpp new file mode 100644 index 0000000..d21ac42 --- /dev/null +++ b/include/boost/functional/lightweight_forward_adapter.hpp @@ -0,0 +1,259 @@ +/*============================================================================= + 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_LIGHTWEIGHT_FORWARD_ADAPTER_HPP_INCLUDED +# ifndef BOOST_PP_IS_ITERATING + +# include +# include + +# include +# include +# include +# include +# include +# include + +# include +# include + +# ifndef BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY +# define BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY 10 +# elif BOOST_FUNCTIONAL_FORDWARD_ADAPTER_MAX_ARITY < 3 +# undef BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY +# define BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY 3 +# endif + +namespace boost +{ + template< typename Function, int Arity_Or_MinArity = -1, int MaxArity = -1 > + class lightweight_forward_adapter; + + //----- ---- --- -- - - - - + + namespace detail + { + template< class MostDerived, typename Function, typename FunctionConst, + int Arity, int MinArity > + struct lightweight_forward_adapter_impl; + + struct lightweight_forward_adapter_result + { + template< typename Sig > struct apply; + + // Utility metafunction for argument transform + template< typename T > struct x { typedef T const& t; }; + template< typename T > struct x< boost::reference_wrapper > + { typedef T& t; }; + template< typename T > struct x : x { }; + template< typename T > struct x : x { }; + template< typename T > struct x : x { }; + + // Utility metafunction to choose target function qualification + template< typename T > struct c + { typedef typename T::target_function_t t; }; + template< typename T > struct c + { typedef typename T::target_function_t t; }; + template< typename T > struct c + { typedef typename T::target_function_const_t t; }; + template< typename T > struct c + { typedef typename T::target_function_const_t t; }; + }; + } + +# define BOOST_TMP_MACRO(f,fn,fc) \ + boost::detail::lightweight_forward_adapter_impl< \ + lightweight_forward_adapter, fn, fc, \ + (MaxArity!=-1? MaxArity :Arity_Or_MinArity!=-1? Arity_Or_MinArity \ + :BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY), \ + (Arity_Or_MinArity!=-1? Arity_Or_MinArity : 0) > + + template< typename Function, int Arity_Or_MinArity, int MaxArity > + class lightweight_forward_adapter + : public BOOST_TMP_MACRO(Function,Function,Function const) + , private Function + { + public: + lightweight_forward_adapter(Function const& f = Function()) + : Function(f) + { } + + typedef Function target_function_t; + typedef Function const target_function_const_t; + + Function & target_function() { return *this; } + Function const & target_function() const { return *this; } + + template< typename Sig > struct result + : detail::lightweight_forward_adapter_result::template apply + { }; + + using BOOST_TMP_MACRO(Function,Function, Function const)::operator(); + }; + template< typename Function, int Arity_Or_MinArity, int MaxArity > + class lightweight_forward_adapter< Function const, Arity_Or_MinArity, + MaxArity > + : public BOOST_TMP_MACRO(Function const, Function const, Function const) + , private Function + { + public: + lightweight_forward_adapter(Function const& f = Function()) + : Function(f) + { } + + typedef Function const target_function_t; + typedef Function const target_function_const_t; + + Function const & target_function() const { return *this; } + + template< typename Sig > struct result + : detail::lightweight_forward_adapter_result::template apply + { }; + + using BOOST_TMP_MACRO(Function const,Function const, Function const) + ::operator(); + }; + template< typename Function, int Arity_Or_MinArity, int MaxArity > + class lightweight_forward_adapter< Function &, Arity_Or_MinArity, MaxArity > + : public BOOST_TMP_MACRO(Function&, Function, Function) + { + Function& ref_function; + public: + lightweight_forward_adapter(Function& f) + : ref_function(f) + { } + + typedef Function target_function_t; + typedef Function target_function_const_t; + + Function & target_function() const { return this->ref_function; } + + template< typename Sig > struct result + : detail::lightweight_forward_adapter_result::template apply + { }; + + using BOOST_TMP_MACRO(Function&, Function, Function)::operator(); + }; + + #undef BOOST_TMP_MACRO + + namespace detail + { + template< class Self > + struct lightweight_forward_adapter_result::apply< Self() > + : boost::result_of< typename c::t() > + { }; + + template< class MD, class F, class FC > + struct lightweight_forward_adapter_impl + : lightweight_forward_adapter_result + { + inline typename boost::result_of< FC() >::type + operator()() const + { + return static_cast(this)->target_function()(); + } + + inline typename boost::result_of< F() >::type + operator()() + { + return static_cast(this)->target_function()(); + } + }; + +# define BOOST_PP_FILENAME_1 \ + +# define BOOST_PP_ITERATION_LIMITS \ + (1,BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_MAX_ARITY) +# include BOOST_PP_ITERATE() + + } // namespace detail + + template + struct result_of const ()> + : boost::detail::lightweight_forward_adapter_result::template apply< + boost::lightweight_forward_adapter const () > + { }; + template + struct result_of()> + : boost::detail::lightweight_forward_adapter_result::template apply< + boost::lightweight_forward_adapter() > + { }; + template + struct result_of const& ()> + : boost::detail::lightweight_forward_adapter_result::template apply< + boost::lightweight_forward_adapter const () > + { }; + template + struct result_of& ()> + : boost::detail::lightweight_forward_adapter_result::template apply< + boost::lightweight_forward_adapter() > + { }; +} + +# define BOOST_FUNCTIONAL_LIGHTWEIGHT_FORWARD_ADAPTER_HPP_INCLUDED + +# else // defined(BOOST_PP_IS_ITERATING) +# define N BOOST_PP_ITERATION() + + template< class Self, BOOST_PP_ENUM_PARAMS(N,typename T) > + struct lightweight_forward_adapter_result::apply< + Self (BOOST_PP_ENUM_PARAMS(N,T)) > + : boost::result_of< + typename c::t (BOOST_PP_ENUM_BINARY_PARAMS(N, + typename x::t BOOST_PP_INTERCEPT)) > + { }; + + template< class MD, class F, class FC > + struct lightweight_forward_adapter_impl + : lightweight_forward_adapter_result + { + template< BOOST_PP_ENUM_PARAMS(N,typename T) > + inline typename boost::result_of< F(BOOST_PP_ENUM_BINARY_PARAMS(N, + T,const& BOOST_PP_INTERCEPT)) >::type + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,& BOOST_PP_INTERCEPT)); + }; + + template< class MD, class F, class FC, int MinArity > + struct lightweight_forward_adapter_impl + : lightweight_forward_adapter_impl + { + using lightweight_forward_adapter_impl::operator(); + +# define M(z,i,d) \ + static_cast::t>(a##i) + + template< BOOST_PP_ENUM_PARAMS(N,typename T) > + inline typename lightweight_forward_adapter_result::template apply< + MD const (BOOST_PP_ENUM_BINARY_PARAMS(N, + T,const& BOOST_PP_INTERCEPT)) >::type + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const& a)) const + { + typedef lightweight_forward_adapter_result _; + return static_cast(this)->target_function()( + BOOST_PP_ENUM(N,M,_)); + } + template< BOOST_PP_ENUM_PARAMS(N,typename T) > + inline typename lightweight_forward_adapter_result::template apply< + MD (BOOST_PP_ENUM_BINARY_PARAMS(N, + T,const& BOOST_PP_INTERCEPT)) >::type + operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,const& a)) + { + typedef lightweight_forward_adapter_result _; + return static_cast(this)->target_function()( + BOOST_PP_ENUM(N,M,_)); + } +# undef M + }; + +# undef N +# endif // defined(BOOST_PP_IS_ITERATING) + +#endif // include guard +