blob: 29e918a352a08e4488850c238d953fc1fcd3c1f8 [file] [log] [blame]
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Extending Actors</title>
<link rel="stylesheet" href="../../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.76.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Phoenix 3.0">
<link rel="up" href="../inside.html" title="Inside Phoenix">
<link rel="prev" href="expression/phoenix_define_expression_ext_vararg.html" title="PHOENIX_DEFINE_EXPRESSION_EXT_VARARG">
<link rel="next" href="custom_terminals.html" title="Custom Terminals">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr><td valign="top"></td></tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="expression/phoenix_define_expression_ext_vararg.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../inside.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="custom_terminals.html"><img src="../../images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="phoenix.inside.extending_actors"></a><a class="link" href="extending_actors.html" title="Extending Actors">Extending Actors</a>
</h3></div></div></div>
<p>
<a class="link" href="actor.html" title="Actors in Detail">Actors</a> are one of the main parts
of the library, and one of the many customization points. The default actor
implementation provides several operator() overloads which deal with the
evaluation of expressions.
</p>
<p>
For some uses cases this might not be enough. For convenience it is thinkable
to provide custom member functions which generate new expressions. An example
is the <a class="link" href="../modules/statement/___if_else_____statement.html" title="if_else_ Statement">if_else_
Statement</a>
which provides an additional else member for generating a lazy if-else expression.
With this the actual Phoenix expression becomes more expressive.
</p>
<p>
Another scenario is to give actors the semantics of a certain well known
interface or concept. This tutorial like section will provide information
on how to implement a custom actor which is usable as if it were a <a href="http://www.sgi.com/tech/stl/Container.html" target="_top">STL Container</a>.
</p>
<a name="phoenix.inside.extending_actors.requirements"></a><h5>
<a name="id705278"></a>
<a class="link" href="extending_actors.html#phoenix.inside.extending_actors.requirements">Requirements</a>
</h5>
<p>
Let's repeat what we want to have:
</p>
<div class="informaltable"><table class="table">
<colgroup>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Expression
</p>
</th>
<th>
<p>
Semantics
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">begin</span><span class="special">()</span></code>
</p>
</td>
<td>
<p>
Returns an iterator pointing to the first element in the container.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">end</span><span class="special">()</span></code>
</p>
</td>
<td>
<p>
Returns an iterator pointing one past the last element in the container.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">size</span><span class="special">()</span></code>
</p>
</td>
<td>
<p>
Returns the size of the container, that is, its number of elements.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">max_size</span><span class="special">()</span></code>
</p>
</td>
<td>
<p>
Returns the largest size that this container can ever have.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">empty</span><span class="special">()</span></code>
</p>
</td>
<td>
<p>
Equivalent to a.size() == 0. (But possibly faster.)
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">a</span><span class="special">.</span><span class="identifier">swap</span><span class="special">(</span><span class="identifier">b</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
Equivalent to swap(a,b)
</p>
</td>
</tr>
</tbody>
</table></div>
<p>
Additionally, we want all the operator() overloads of the regular actor.
</p>
<a name="phoenix.inside.extending_actors.defining_the_actor"></a><h5>
<a name="id705590"></a>
<a class="link" href="extending_actors.html#phoenix.inside.extending_actors.defining_the_actor">Defining
the actor</a>
</h5>
<p>
The first version of our <code class="computeroutput"><span class="identifier">container_actor</span></code>
interface will show the general principle. This will be continually extended.
For the sake of simplicity, every member function generator will return
<a class="link" href="../modules/core/nothing.html" title="Nothing"><code class="computeroutput"><span class="identifier">nothing</span></code></a>
at first.
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">container_actor</span>
<span class="special">:</span> <span class="identifier">actor</span><span class="special">&lt;</span><span class="identifier">Expr</span><span class="special">&gt;</span>
<span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">actor</span><span class="special">&lt;</span><span class="identifier">Expr</span><span class="special">&gt;</span> <span class="identifier">base_type</span><span class="special">;</span>
<span class="keyword">typedef</span> <span class="identifier">container_actor</span><span class="special">&lt;</span><span class="identifier">Expr</span><span class="special">&gt;</span> <span class="identifier">that_type</span><span class="special">;</span>
<span class="identifier">container_actor</span><span class="special">(</span> <span class="identifier">base_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">base</span> <span class="special">)</span>
<span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span> <span class="identifier">base</span> <span class="special">)</span> <span class="special">{}</span>
<span class="identifier">expression</span><span class="special">::</span><span class="identifier">null</span><span class="special">&lt;</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">void_</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">begin</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">nothing</span><span class="special">;</span> <span class="special">}</span>
<span class="identifier">expression</span><span class="special">::</span><span class="identifier">null</span><span class="special">&lt;</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">void_</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">end</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">nothing</span><span class="special">;</span> <span class="special">}</span>
<span class="identifier">expression</span><span class="special">::</span><span class="identifier">null</span><span class="special">&lt;</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">void_</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">size</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">nothing</span><span class="special">;</span> <span class="special">}</span>
<span class="identifier">expression</span><span class="special">::</span><span class="identifier">null</span><span class="special">&lt;</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">void_</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">max_size</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">nothing</span><span class="special">;</span> <span class="special">}</span>
<span class="identifier">expression</span><span class="special">::</span><span class="identifier">null</span><span class="special">&lt;</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">void_</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">empty</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">nothing</span><span class="special">;</span> <span class="special">}</span>
<span class="comment">// Note that swap is the only function needing another container.
</span> <span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Container</span><span class="special">&gt;</span>
<span class="identifier">expression</span><span class="special">::</span><span class="identifier">null</span><span class="special">&lt;</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">void_</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">swap</span><span class="special">(</span> <span class="identifier">actor</span><span class="special">&lt;</span><span class="identifier">Container</span><span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">nothing</span><span class="special">;</span> <span class="special">}</span>
<span class="special">};</span>
</pre>
<a name="phoenix.inside.extending_actors.using_the_actor"></a><h5>
<a name="id706473"></a>
<a class="link" href="extending_actors.html#phoenix.inside.extending_actors.using_the_actor">Using the
actor</a>
</h5>
<p>
Although the member functions do nothing right now, we want to test if we
can use our new actor.
</p>
<p>
First, lets create a generator which wraps the <code class="computeroutput"><span class="identifier">container_actor</span></code>
around any other expression:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">&gt;</span>
<span class="identifier">container_actor</span><span class="special">&lt;</span><span class="identifier">Expr</span><span class="special">&gt;</span> <span class="keyword">const</span>
<span class="identifier">container</span><span class="special">(</span> <span class="identifier">actor</span><span class="special">&lt;</span><span class="identifier">Expr</span><span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">expr</span> <span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">expr</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
Now let's test this:
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">v</span><span class="special">;</span>
<span class="identifier">v</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">0</span><span class="special">);</span>
<span class="identifier">v</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">1</span><span class="special">);</span>
<span class="identifier">v</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">2</span><span class="special">);</span>
<span class="identifier">v</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">3</span><span class="special">);</span>
<span class="special">(</span><span class="identifier">container</span><span class="special">(</span><span class="identifier">arg1</span><span class="special">).</span><span class="identifier">size</span><span class="special">())(</span><span class="identifier">v</span><span class="special">);</span>
</pre>
<p>
Granted, this is not really elegant and not very practical (we could have
just used phoenix::begin(v) from the <a class="link" href="../modules/stl/algorithm.html" title="Algorithm">Phoenix
algorithm module</a>, but we can do better.
</p>
<p>
Let's have an <a class="link" href="../modules/core/arguments.html" title="Arguments">argument placeholder</a>
which is usable as if it was a STL container:
</p>
<pre class="programlisting"><span class="identifier">container_actor</span><span class="special">&lt;</span><span class="identifier">expression</span><span class="special">::</span><span class="identifier">argument</span><span class="special">&lt;</span><span class="number">1</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">&gt;</span> <span class="keyword">const</span> <span class="identifier">con1</span><span class="special">;</span>
<span class="comment">// and so on ...
</span></pre>
<p>
The above example can be rewritten as:
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">v</span><span class="special">;</span>
<span class="identifier">v</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">0</span><span class="special">);</span>
<span class="identifier">v</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">1</span><span class="special">);</span>
<span class="identifier">v</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">2</span><span class="special">);</span>
<span class="identifier">v</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">3</span><span class="special">);</span>
<span class="special">(</span><span class="identifier">con1</span><span class="special">.</span><span class="identifier">size</span><span class="special">())(</span><span class="identifier">v</span><span class="special">);</span>
</pre>
<p>
Wow, that was easy!
</p>
<a name="phoenix.inside.extending_actors.adding_life_to_the_actor"></a><h5>
<a name="id707140"></a>
<a class="link" href="extending_actors.html#phoenix.inside.extending_actors.adding_life_to_the_actor">Adding
life to the actor</a>
</h5>
<p>
This one will be even easier!
</p>
<p>
First, we define a <a class="link" href="../modules/function.html" title="Function">lazy function</a>
which evaluates the expression we want to implement. Following is the implementation
of the size function:
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">size_impl</span>
<span class="special">{</span>
<span class="comment">// result_of protocol:
</span> <span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Sig</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">result</span><span class="special">;</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">This</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Container</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">result</span><span class="special">&lt;</span><span class="identifier">This</span><span class="special">(</span><span class="identifier">Container</span><span class="special">)&gt;</span>
<span class="special">{</span>
<span class="comment">// Note, remove reference here, because Container can be anything
</span> <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special">&lt;</span><span class="identifier">Container</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">container_type</span><span class="special">;</span>
<span class="comment">// The result will be size_type
</span> <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">container_type</span><span class="special">::</span><span class="identifier">size_type</span> <span class="identifier">type</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Container</span><span class="special">&gt;</span>
<span class="keyword">typename</span> <span class="identifier">result</span><span class="special">&lt;</span><span class="identifier">size_impl</span><span class="special">(</span><span class="identifier">Container</span> <span class="keyword">const</span><span class="special">&amp;)&gt;::</span><span class="identifier">type</span>
<span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Container</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">container</span><span class="special">)</span> <span class="keyword">const</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">container</span><span class="special">.</span><span class="identifier">size</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
Good, this was the first part. The second part will be to implement the size
member function of <code class="computeroutput"><span class="identifier">container_actor</span></code>:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">container_actor</span>
<span class="special">:</span> <span class="identifier">actor</span><span class="special">&lt;</span><span class="identifier">Expr</span><span class="special">&gt;</span>
<span class="special">{</span>
<span class="keyword">typedef</span> <span class="identifier">actor</span><span class="special">&lt;</span><span class="identifier">Expr</span><span class="special">&gt;</span> <span class="identifier">base_type</span><span class="special">;</span>
<span class="keyword">typedef</span> <span class="identifier">container_actor</span><span class="special">&lt;</span><span class="identifier">Expr</span><span class="special">&gt;</span> <span class="identifier">that_type</span><span class="special">;</span>
<span class="identifier">container_actor</span><span class="special">(</span> <span class="identifier">base_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">base</span> <span class="special">)</span>
<span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span> <span class="identifier">base</span> <span class="special">)</span> <span class="special">{}</span>
<span class="keyword">typename</span> <span class="identifier">expression</span><span class="special">::</span><span class="identifier">function</span><span class="special">&lt;</span><span class="identifier">size_impl</span><span class="special">,</span> <span class="identifier">that_type</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="keyword">const</span>
<span class="identifier">size</span><span class="special">()</span> <span class="keyword">const</span>
<span class="special">{</span>
<span class="identifier">function</span><span class="special">&lt;</span><span class="identifier">size_impl</span><span class="special">&gt;</span> <span class="keyword">const</span> <span class="identifier">f</span> <span class="special">=</span> <span class="identifier">size_impl</span><span class="special">();</span>
<span class="keyword">return</span> <span class="identifier">f</span><span class="special">(*</span><span class="keyword">this</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">// the rest ...
</span><span class="special">};</span>
</pre>
<p>
It is left as an exercise to the user to implement the missing parts by reusing
functions from the <a class="link" href="../modules/stl/algorithm.html" title="Algorithm">Phoenix
Algorithm Module</a> (the impatient take a look here: <a href="../../../../example/container_actor.cpp" target="_top">container_actor.cpp</a>).
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2002-2005, 2010 Joel de Guzman, Dan Marsden, Thomas Heller<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="expression/phoenix_define_expression_ext_vararg.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../inside.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="custom_terminals.html"><img src="../../images/next.png" alt="Next"></a>
</div>
</body>
</html>