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

130 lines
12 KiB
HTML

<html>
<head>
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
<title>Actors revisited</title>
<link rel="stylesheet" href="theme/style.css" type="text/css">
<link rel="prev" href="tuples.html">
<link rel="next" href="composites_revisited.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>Actors revisited</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="tuples.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="composites_revisited.html"><img src="theme/r_arr.gif" border="0"></a></td>
</tr>
</table>
<p>
This class is a protocol class for all actors. This class is essentially an interface contract. The actor class does not really know how how to act on anything but instead relies on the template parameter BaseT (from which the actor will derive from) to do the actual action. The template class actor is declared as:</p>
<code><pre>
<span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>BaseT</span><span class=special>&gt;
</span><span class=keyword>struct </span><span class=identifier>actor </span><span class=special>: </span><span class=keyword>public </span><span class=identifier>BaseT </span><span class=special>{
</span><span class=identifier>actor</span><span class=special>();
</span><span class=identifier>actor</span><span class=special>(</span><span class=identifier>BaseT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>base</span><span class=special>);
/*...</span><span class=identifier>member </span><span class=identifier>functions</span><span class=special>...*/
};
</span></pre></code>
<table width="80%" border="0" align="center">
<tr>
<td class="note_box">
<img src="theme/lens.gif"></img> <b>Curiously Recurring Template Pattern Inverse</b><br><br>Notice that actor derives from its template argument BaseT. This is the inverse of the curiously recurring template pattern (CRTP). With the CRTP, the actor is an abstract class with a DerivedT template parameter that is assumed to be its parametric subclass. This pattern however, &quot;parametric base class pattern&quot; (PBCP) for lack of a name, inverses the inheritance and makes actor a concrete class. Anyway, be it CRTP or PBCP, actor is a protocol class and either BaseT or DerivedT will have to conform to its protocol. Both CRTP and PBCP techniques has its pros and cons, of which is outside the scope of this document. CRTP should really be renamed &quot;parametric subclass pattern (PSCP), but again, that's another story. </td>
</tr>
</table>
<p>
An actor is a functor that is capable of accepting arguments up to a predefined maximum. It is up to the base class to do the actual processing or possibly to limit the arity (no. of arguments) passed in. Upon invocation of the functor through a supplied operator(), the actor funnels the arguments passed in by the client into a tuple and calls the base class' eval member function.</p>
<p>
Schematically:</p>
<code>
<pre>
<span class=identifier>arg0 </span><span class=special>---------|
</span><span class=identifier>arg1 </span><span class=special>---------|
</span><span class=identifier>arg2 </span><span class=special>---------|---&gt; </span><span class=identifier>tupled_args </span><span class=special>---&gt; </span><span class=identifier>base</span><span class=special>.</span><span class=identifier>eval
</span><span class=special>... |
</span><span class=identifier>argN </span><span class=special>---------|
</span><span class=identifier>actor</span><span class=special>::</span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>arg0</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>... </span><span class=identifier>argN</span><span class=special>)
---&gt; </span><span class=identifier>BaseT</span><span class=special>::</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>tupled_args</span><span class=special>);
</span></pre>
</code>
<p>
Actor base classes from which this class inherits from are expected to have a corresponding member function eval compatible with the conceptual Interface:</p>
<code><pre>
<span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
</span><span class=identifier>actor_return_type
</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>TupleT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>args</span><span class=special>) </span><span class=keyword>const</span><span class=special>;
</span></pre></code>
<p>
where args are the actual arguments passed in by the client funneled into a tuple (see tuple for details).</p>
<p>
The actor_return_type can be anything. Base classes are free to return any type, even argument dependent types (types that are deduced from the types of the arguments). After evaluating the parameters and doing some computations or actions, the eval member function concludes by returning something back to the client. To do this, the forwarding function (the actor's operator()) needs to know the return type of the eval member function that it is calling. For this purpose, actor base classes are required to provide a nested template class:</p>
<code><pre>
<span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
</span><span class=keyword>struct </span><span class=identifier>result</span><span class=special>;
</span></pre></code>
<p>
This auxiliary class provides the result type information returned by the eval member function of a base actor class. The nested template class result should have a typedef 'type' that reflects the return type of its member function eval. It is basically a type computer that answers the question &quot;given arguments packed into a TupleT type, what will be the result type of the eval member function of ActorT?&quot;.</p>
<p>
There is a global template class actor_result declared in namespace phoenix scope that queries the actor's result type given a tuple. Here is the class actor_result's declaration:</p>
<code><pre>
<span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>ActorT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
</span><span class=keyword>struct </span><span class=identifier>actor_result </span><span class=special>{
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>ActorT</span><span class=special>::</span><span class=keyword>template </span><span class=identifier>result</span><span class=special>&lt;</span><span class=identifier>TupleT</span><span class=special>&gt;::</span><span class=identifier>type </span><span class=identifier>type</span><span class=special>;
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>remove_reference</span><span class=special>&lt;</span><span class=identifier>type</span><span class=special>&gt;::</span><span class=identifier>type </span><span class=identifier>plain_type</span><span class=special>;
};
</span></pre></code>
<ul><li>type is the actual return type</li><li>plain_type is the return type stripped from references.</li></ul><p>
Given an actor type ActorT and a TupleT, we can get the actor's return type this way:</p>
<code><pre>
<span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special>&lt;</span><span class=identifier>ActorT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>&gt;::</span><span class=identifier>type
</span><span class=identifier>actor_return_type</span><span class=special>;
</span></pre></code>
<p>
where actor_return_type is the actual type returned by ActorT's eval member function given some arguments packed in a TupleT.</p>
<p>
For reference, here's a typical actor::operator() that accepts two (2) arguments:</p>
<code><pre>
<span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>BaseT</span><span class=special>&gt;
</span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>&gt;
</span><span class=keyword>inline </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special>&lt;</span><span class=identifier>BaseT</span><span class=special>, </span><span class=identifier>tuple</span><span class=special>&lt;</span><span class=identifier>T0</span><span class=special>&amp;, </span><span class=identifier>T1</span><span class=special>&amp;&gt; &gt;::</span><span class=identifier>type
</span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>BaseT</span><span class=special>&gt;::</span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>T0</span><span class=special>&amp; </span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&amp; </span><span class=identifier>_1</span><span class=special>) </span><span class=keyword>const
</span><span class=special>{
</span><span class=keyword>return </span><span class=identifier>BaseT</span><span class=special>::</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>tuple</span><span class=special>&lt;</span><span class=identifier>T0</span><span class=special>&amp;, </span><span class=identifier>T1</span><span class=special>&amp;&gt;(</span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>_1</span><span class=special>));
}
</span></pre></code>
<table width="80%" border="0" align="center">
<tr>
<td class="note_box">
<img src="theme/lens.gif"></img> <b>Forwarding Function Problem</b><br><br>_0 and _1 are references. Hence the arguments cannot accept non-const temporaries and literal constants. This is a current C++ language issue known as the &quot;forwarding function problem&quot; that is currently being discussed. The problem is that given an arbitrary function f, using current C++ language rules, one cannot create a forwarding function f' that transparently assumes the arguments of f. </td>
</tr>
</table>
<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="tuples.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="composites_revisited.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<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> </p>
</body>
</html>