spirit/classic/phoenix/doc/binders.html
Joel de Guzman 994d4e48cc moving stuff to classic spirit
[SVN r44163]
2008-04-10 23:51:31 +00:00

182 lines
17 KiB
HTML

<html>
<head>
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
<title>Binders</title>
<link rel="stylesheet" href="theme/style.css" type="text/css">
<link rel="prev" href="statements.html">
<link rel="next" href="adaptable_closures.html">
</head>
<body>
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
<tr>
<td width="10">
</td>
<td width="85%">
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Binders</b></font>
</td>
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
</tr>
</table>
<br>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="statements.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="adaptable_closures.html"><img src="theme/r_arr.gif" border="0"></a></td>
</tr>
</table>
<p>
There are times when it is desireable to bind a simple functor, function, member function or member variable for deferred evaluation. This can be done through the binding facilities provided below. There are template classes:</p>
<ol><li>function_ptr ( function pointer binder )</li><li>functor ( functor pointer binder )</li><li>member_function_ptr ( member function pointer binder )</li><li>member_var_ptr ( member variable pointer binder )</li></ol><p>
These template classes are specialized lazy function classes for functors, function pointers, member function pointers and member variable pointers, respectively. These are subclasses of the lazy- function class (see functions). Each of these has a corresponding overloaded bind(x) function. Each bind(x) function generates a suitable binder object.</p>
<p>
Example, given a function foo:</p>
<code><pre>
<span class=keyword>void </span><span class=identifier>foo_</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>n</span><span class=special>) { </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special>&lt;&lt; </span><span class=identifier>n </span><span class=special>&lt;&lt; </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>; }
</span></pre></code>
<p>
Here's how the function foo is bound:</p>
<code><pre>
<span class=identifier>bind</span><span class=special>(&amp;</span><span class=identifier>foo_</span><span class=special>)
</span></pre></code>
<p>
This bind expression results to a lazy-function (see functions) that is lazily evaluated. This bind expression is also equivalent to:</p>
<code><pre>
<span class=identifier>function_ptr</span><span class=special>&lt;</span><span class=keyword>void</span><span class=special>, </span><span class=keyword>int</span><span class=special>&gt; </span><span class=identifier>foo </span><span class=special>= &amp;</span><span class=identifier>foo_</span><span class=special>;
</span></pre></code>
<p>
The template parameter of the function_ptr is the return and argument types of actual signature of the function to be bound read from left to right. Examples:</p>
<code><pre>
<span class=keyword>void </span><span class=identifier>foo_</span><span class=special>(</span><span class=keyword>int</span><span class=special>); ---&gt; </span><span class=identifier>function_ptr</span><span class=special>&lt;</span><span class=keyword>void</span><span class=special>, </span><span class=keyword>int</span><span class=special>&gt;
</span><span class=keyword>int </span><span class=identifier>bar_</span><span class=special>(</span><span class=keyword>double</span><span class=special>, </span><span class=keyword>int</span><span class=special>); ---&gt; </span><span class=identifier>function_ptr</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double</span><span class=special>, </span><span class=keyword>int</span><span class=special>&gt;
</span></pre></code>
<p>
Either bind(&amp;foo_) and its equivalent foo can now be used in the same way a lazy function (see functions) is used:</p>
<code><pre>
<span class=identifier>bind</span><span class=special>(&amp;</span><span class=identifier>foo_</span><span class=special>)(</span><span class=identifier>arg1</span><span class=special>)
</span></pre></code>
<p>
or</p>
<code><pre>
<span class=identifier>foo</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)
</span></pre></code>
<p>
The latter, of course, follows C/C++ function call syntax and is much easier to understand. This is now a full-fledged lazy function that can finally be evaluated by another function call invocation. A second function call will invoke the actual foo function:</p>
<code><pre>
<span class=keyword>int </span><span class=identifier>i </span><span class=special>= </span><span class=number>4</span><span class=special>;
</span><span class=identifier>foo</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)(</span><span class=identifier>i</span><span class=special>);
</span></pre></code>
<p>
will print out &quot;4&quot;.</p>
<p>
Binding functors and member functions can be done similarly. Here's how to bind a functor (e.g. std::plus&lt;int&gt;):</p>
<code><pre>
<span class=identifier>bind</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>plus</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;())
</span></pre></code>
<p>
or</p>
<code><pre>
<span class=identifier>functor</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>plus</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt; &gt; </span><span class=identifier>plus</span><span class=special>;
</span></pre></code>
<p>
Again, these are full-fledged lazy functions. In this case, unlike the first example, expect 2 arguments (std::plus&lt;int&gt; needs two arguments lhs and rhs). Either or both of which can be lazily bound:</p>
<code><pre>
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>) // </span><span class=identifier>arg1 </span><span class=special>+ </span><span class=identifier>arg2
</span><span class=identifier>plus</span><span class=special>(</span><span class=number>100</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>) // </span><span class=number>100 </span><span class=special>+ </span><span class=identifier>arg1
</span><span class=identifier>plus</span><span class=special>(</span><span class=number>100</span><span class=special>, </span><span class=number>200</span><span class=special>) // </span><span class=number>300
</span></pre></code>
<p>
A bound member function takes in a pointer or reference to an object as the first argument. For instance, given:</p>
<code><pre>
<span class=keyword>struct </span><span class=identifier>xyz </span><span class=special>{ </span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>int</span><span class=special>) </span><span class=keyword>const</span><span class=special>; };
</span></pre></code>
<p>
xyz's foo member function can be bound as:</p>
<code><pre>
<span class=identifier>bind</span><span class=special>(&amp;</span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>foo</span><span class=special>)
</span></pre></code>
<p>
or</p>
<p>
member_function_ptr&lt;void, xyz, int&gt; xyz_foo = &amp;xyz::foo;</p>
<p>
The template parameter of the member_function_ptr is the return, class and argument types of actual signature of the function to be bound, read from left to right:</p>
<code>
<pre>
<span class=keyword>void </span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>foo_</span><span class=special>(</span><span class=keyword>int</span><span class=special>); ---&gt; </span><span class=identifier>member_function_ptr</span><span class=special>&lt;</span><span class=keyword>void</span><span class=special>, </span><span class=identifier>xyz</span><span class=special>, </span><span class=keyword>int</span><span class=special>&gt;
</span><span class=keyword>int </span><span class=identifier>abc</span><span class=special>::</span><span class=identifier>bar_</span><span class=special>(</span><span class=keyword>double</span><span class=special>, </span><span class=keyword>char</span><span class=special>); ---&gt; </span><span class=identifier>member_function_ptr</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>abc</span><span class=special>, </span><span class=keyword>double</span><span class=special>, </span><span class=keyword>char</span><span class=special>&gt;
</span></pre>
</code>
<p>
Take note that a member_function_ptr lazy-function expects the first argument to be a pointer or reference to an object. Both the object (reference or pointer) and the arguments can be lazily bound. Examples:</p>
<code><pre>
<span class=identifier>xyz </span><span class=identifier>obj</span><span class=special>;
</span><span class=identifier>xyz_foo</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>) // </span><span class=identifier>arg1</span><span class=special>.</span><span class=identifier>foo</span><span class=special>(</span><span class=identifier>arg2</span><span class=special>)
</span><span class=identifier>xyz_foo</span><span class=special>(</span><span class=identifier>obj</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>) // </span><span class=identifier>obj</span><span class=special>.</span><span class=identifier>foo</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)
</span><span class=identifier>xyz_foo</span><span class=special>(</span><span class=identifier>obj</span><span class=special>, </span><span class=number>100</span><span class=special>) // </span><span class=identifier>obj</span><span class=special>.</span><span class=identifier>foo</span><span class=special>(</span><span class=number>100</span><span class=special>)
</span></pre></code>
<p>
Be reminded that var(obj) must be used to call non-const member functions. For example, if xyz was declared as:</p>
<code><pre>
<span class=keyword>struct </span><span class=identifier>xyz </span><span class=special>{ </span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>int</span><span class=special>); }; // </span><span class=identifier>note </span><span class=identifier>non</span><span class=special>-</span><span class=keyword>const </span><span class=identifier>member </span><span class=identifier>function
</span></pre></code>
<p>
the pointer or reference to the object must also be non-const since lazily bound arguments are stored as const value by default (see variable class in primitives).</p>
<code><pre>
<span class=identifier>xyz_foo</span><span class=special>(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>obj</span><span class=special>), </span><span class=number>100</span><span class=special>) // </span><span class=identifier>obj</span><span class=special>.</span><span class=identifier>foo</span><span class=special>(</span><span class=number>100</span><span class=special>)
</span></pre></code>
<p>
arg1..argN are already implicitly mutable. There is no need to wrap arg1..argN in a var. It is an error to do so:</p>
<code><pre>
<span class=identifier>var</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>) // </span><span class=identifier>ERROR</span><span class=special>! </span><span class=identifier>arg1 </span><span class=identifier>is </span><span class=identifier>already </span><span class=keyword>mutable
</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>arg2</span><span class=special>) // </span><span class=identifier>ERROR</span><span class=special>! </span><span class=identifier>arg2 </span><span class=identifier>is </span><span class=identifier>already </span><span class=keyword>mutable
</span></pre></code>
<p>
Finally, member variables can be bound much like member functions. For instance, given:</p>
<code><pre>
<span class=keyword>struct </span><span class=identifier>xyz </span><span class=special>{ </span><span class=keyword>int </span><span class=identifier>v</span><span class=special>; };
</span></pre></code>
<p>
xyz::v can be bound as:</p>
<code><pre>
<span class=identifier>bind</span><span class=special>(&amp;</span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>v</span><span class=special>)
</span></pre></code>
<p>
or</p>
<code><pre>
<span class=identifier>member_var_ptr</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>xyz</span><span class=special>&gt; </span><span class=identifier>xyz_v </span><span class=special>= &amp;</span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>v</span><span class=special>;
</span></pre></code>
<p>
The template parameter of the member_var_ptr is the type of the variable followed by the class:</p>
<code><pre>
<span class=keyword>int </span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>v</span><span class=special>; ---&gt; </span><span class=identifier>member_var_ptr</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>xyz</span><span class=special>&gt;
</span></pre></code>
<p>
Just like the member_function_ptr, member_var_ptr also expects the first argument to be a pointer or reference to an object. Both the object (reference or pointer) and the arguments can be lazily bound. Like member function binders, var(obj) must be used to access non-const member variables. Examples:</p>
<code><pre>
<span class=identifier>xyz </span><span class=identifier>obj</span><span class=special>;
</span><span class=identifier>xyz_v</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>) // </span><span class=identifier>arg1</span><span class=special>.</span><span class=identifier>v </span><span class=special>(</span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>access</span><span class=special>)
</span><span class=identifier>xyz_v</span><span class=special>(</span><span class=identifier>obj</span><span class=special>) // </span><span class=identifier>obj</span><span class=special>.</span><span class=identifier>v </span><span class=special>(</span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>access</span><span class=special>)
</span><span class=identifier>xyz_v</span><span class=special>(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>obj</span><span class=special>))() = </span><span class=number>3 </span><span class=comment>// obj.v = 3 (non-const&amp; access)
</span><span class=identifier>xyz_v</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)(</span><span class=identifier>obj</span><span class=special>) = </span><span class=number>4 </span><span class=comment>// obj.v = 4 (non-const&amp; access)
</span></pre></code>
<p>
Be reminded once more that binders are monomorphic. This layer is provided only for compatibility with existing code such as prewritten STL functors and legacy APIs. Rather than binding functions or functors, the preferred method is to write true generic and polymorphic lazy-functions (see functions). However, since most of the time we are dealing with adaptation of exisiting code, binders are indeed indespensible.</p>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="statements.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="adaptable_closures.html"><img src="theme/r_arr.gif" border="0"></a></td>
</tr>
</table>
<br>
<hr size="1">
<p class="copyright">Copyright &copy; 2001-2002 Joel de Guzman<font size="2"><br>
<br>
<font size="2">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) </font> </font></p>
</body>
</html>