Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/spirit/phoenix/doc/interfacing.html @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

File size: 46.5 KB
Line 
1<html>
2<head>
3<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
4<title>Interfacing</title>
5<link rel="stylesheet" href="theme/style.css" type="text/css">
6<link rel="prev" href="operators_revisited.html">
7<link rel="next" href="wrap_up.html">
8</head>
9<body>
10<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
11  <tr>
12    <td width="10">
13    </td>
14    <td width="85%">
15      <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Interfacing</b></font>
16    </td>
17    <td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
18  </tr>
19</table>
20<br>
21<table border="0">
22  <tr>
23    <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
24    <td width="30"><a href="operators_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
25    <td width="20"><a href="wrap_up.html"><img src="theme/r_arr.gif" border="0"></a></td>
26   </tr>
27</table>
28<p>
29The modular design of Phoenix makes it extremely extensible. We have seen that layer upon layer, the whole framework is built on a solid foundation. There are only a few simple well designed concepts that are laid out like bricks. Overall the framework is designed to be extended. Everything above the composite and primitives can in fact be considered just as extensions to the framework. This modular design was inherited from the <a href="http://spirit.sourceforge.net">
30Spirit</a> inline parser framework.</p>
31<p>
32Extension is non-intrusive. And, whenever a component or module is extended, the new extension automatically becomes a first class citizen and is automatically recognized by all modules and components in the framework. There are a multitude of ways in which a module is extended.</p>
33<p>
341)  Write and deploy a new primitive:</p>
35<p>
36So far we have presented only a few primitives 1) arguments 2) values and 3) variables. For the sake of illustration, let us write a simple primitive extension. Let us call it static_int. It shall be parameterized by an integer value. It is like a static version of the the value&lt;int&gt; class, but since it is static, holds no data at all. The integer is encoded in its type. Here is the complete class (sample5.cpp):</p>
37<code><pre>
38    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>int </span><span class=identifier>N</span><span class=special>&gt;
39    </span><span class=keyword>struct </span><span class=identifier>static_int </span><span class=special>{
40
41        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
42        </span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{ </span><span class=keyword>typedef </span><span class=keyword>int </span><span class=identifier>type</span><span class=special>; };
43
44        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
45        </span><span class=keyword>int </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=keyword>const </span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>N</span><span class=special>; }
46    };
47</span></pre></code>
48<p>
49That's it. Done! Now we can use this as it is already a full- fledged Phoenix citizen due to interface conformance. Let us write a suitable generator to make it easier to use our static_int. Remember that it should be wrapped as an actor before it can be used. Let us call our generator int_const:</p>
50<code><pre>
51    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>int </span><span class=identifier>N</span><span class=special>&gt;
52    </span><span class=identifier>phoenix</span><span class=special>::</span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>static_int</span><span class=special>&lt;</span><span class=identifier>N</span><span class=special>&gt; &gt;
53    </span><span class=identifier>int_const</span><span class=special>()
54    {
55        </span><span class=keyword>return </span><span class=identifier>static_int</span><span class=special>&lt;</span><span class=identifier>N</span><span class=special>&gt;();
56    }
57</span></pre></code>
58<p>
59Now we are done. Let's use it:</p>
60<code><pre>
61    <span class=identifier>cout </span><span class=special>&lt;&lt; (</span><span class=identifier>int_const</span><span class=special>&lt;</span><span class=number>5</span><span class=special>&gt;() + </span><span class=identifier>int_const</span><span class=special>&lt;</span><span class=number>6</span><span class=special>&gt;())() &lt;&lt; </span><span class=identifier>endl</span><span class=special>;
62</span></pre></code>
63<p>
64Prints out &quot;11&quot;. There are lots of things you can do with this form of extension. For instance, data type casts come to mind. Example:</p>
65<code><pre>
66    <span class=identifier>lazy_cast</span><span class=special>&lt;</span><span class=identifier>T</span><span class=special>&gt;(</span><span class=identifier>some_lazy_expression</span><span class=special>)
67</span></pre></code>
68<p>
692)  Write and deploy a new composite:</p>
70<p>
71This is more complicated than our first example (writing a primitive). Nevertheless, once you get the basics, writing a composite is almost mechanical and boring (read: easy <img src="theme/smiley.gif"></img>). Check out statements.hpp. All the lazy statements are written in terms of the composite interface.</p>
72<p>
73Ok, let's get on with it. Recall that the if_ else_ lazy statement (and all statements for that matter) return void. What's missing, and will surely be useful, is something like C/C++'s &quot;cond ? a : b&quot; expression. It is really unfortunate that C++ fell short of allowing this to be overloaded. Sigh. Anyway here's the code (sample6.cpp):</p>
74<code><pre>
75    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>&gt;
76    </span><span class=keyword>struct </span><span class=identifier>if_else_composite </span><span class=special>{
77
78        </span><span class=keyword>typedef </span><span class=identifier>if_else_composite</span><span class=special>&lt;</span><span class=identifier>CondT</span><span class=special>, </span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>FalseT</span><span class=special>&gt; </span><span class=identifier>self_t</span><span class=special>;
79
80        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
81        </span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
82
83            </span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special>&lt;
84                </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>&gt;::</span><span class=identifier>plain_type</span><span class=special>,
85                </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special>&lt;</span><span class=identifier>FalseT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>&gt;::</span><span class=identifier>plain_type
86            </span><span class=special>&gt;::</span><span class=identifier>type </span><span class=identifier>type</span><span class=special>;
87        };
88
89        </span><span class=identifier>if_else_composite</span><span class=special>(
90            </span><span class=identifier>CondT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>cond_</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>true__</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>false__</span><span class=special>)
91        :   </span><span class=identifier>cond</span><span class=special>(</span><span class=identifier>cond_</span><span class=special>), </span><span class=identifier>true_</span><span class=special>(</span><span class=identifier>true__</span><span class=special>), </span><span class=identifier>false_</span><span class=special>(</span><span class=identifier>false__</span><span class=special>) {}
92
93        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
94        </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special>&lt;</span><span class=identifier>self_t</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>&gt;::</span><span class=identifier>type
95        </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
96        </span><span class=special>{
97            </span><span class=keyword>return </span><span class=identifier>cond</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>) ? </span><span class=identifier>true_</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>) : </span><span class=identifier>false_</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>);
98        }
99
100        </span><span class=identifier>CondT </span><span class=identifier>cond</span><span class=special>; </span><span class=identifier>TrueT </span><span class=identifier>true_</span><span class=special>; </span><span class=identifier>FalseT </span><span class=identifier>false_</span><span class=special>; //  </span><span class=identifier>actors
101    </span><span class=special>};
102</span></pre></code>
103<p>
104Ok, this is quite a mouthfull. Let's digest this piecemeal.</p>
105<code><pre>
106    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>&gt;
107    </span><span class=keyword>struct </span><span class=identifier>if_else_composite </span><span class=special>{
108</span></pre></code>
109<p>
110This is basically a specialized composite that has 3 actors. It has no operation since it is implied. The 3 actors are cond (condition of type CondT) true_ (the true branch of type TrueT), false_ the (false branch or type FalseT).</p>
111<code><pre>
112    <span class=keyword>typedef </span><span class=identifier>if_else_composite</span><span class=special>&lt;</span><span class=identifier>CondT</span><span class=special>, </span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>FalseT</span><span class=special>&gt; </span><span class=identifier>self_t</span><span class=special>;
113</span></pre></code>
114<p>
115self_t is a typedef that declares its own type: &quot;What am I?&quot;</p>
116<code><pre>
117    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
118    </span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
119
120        </span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special>&lt;
121            </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>&gt;::</span><span class=identifier>plain_type</span><span class=special>,
122            </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special>&lt;</span><span class=identifier>FalseT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>&gt;::</span><span class=identifier>plain_type
123        </span><span class=special>&gt;::</span><span class=identifier>type </span><span class=identifier>type</span><span class=special>;
124    };
125</span></pre></code>
126<p>
127We have seen result before. For actor base-classes such as composites and primitives, the parameter is a TupleT, i.e. the tupled arguments passed in from the actor.</p>
128<p>
129So given some arguments, what will be our return type? TrueT and FalseT are also actors remember? So first, we should ask them &quot;What are your *plain* (stripped from references) return types?&quot;</p>
130<p>
131Knowing that, our task is then to know which type has a higher rank (recall rank&lt;T&gt; and higher_rank&lt;T0, T1&gt;). Why do we have to do this? We are emulating the behavior of the &quot;cond ? a : b&quot; expression. In C/C++, the type of this expression is the one (a or b) with the higher rank. For example, if a is an int and b is a double, the result should be a double.</p>
132<p>
133Following this, finally, we have a return type typedef'd by result&lt;TupleT&gt;::type.</p>
134<code><pre>
135    <span class=identifier>if_else_composite</span><span class=special>(
136        </span><span class=identifier>CondT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>cond_</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>true__</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>false__</span><span class=special>)
137    :   </span><span class=identifier>cond</span><span class=special>(</span><span class=identifier>cond_</span><span class=special>), </span><span class=identifier>true_</span><span class=special>(</span><span class=identifier>true__</span><span class=special>), </span><span class=identifier>false_</span><span class=special>(</span><span class=identifier>false__</span><span class=special>) {}
138</span></pre></code>
139<p>
140This is our constructor. We just stuff the constructor arguments into our member variables.</p>
141<code><pre>
142    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>&gt;
143    </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special>&lt;</span><span class=identifier>self_t</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>&gt;::</span><span class=identifier>type
144    </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
145</span></pre></code>
146<p>
147Now, here is our main eval member function. Given a self_t, our type, and the TupleT, the return type deduction is almost canonical. Just ask actor_result, it'll surely know.</p>
148<code><pre>
149    <span class=special>{
150        </span><span class=keyword>return </span><span class=identifier>cond</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>) ? </span><span class=identifier>true_</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>) : </span><span class=identifier>false_</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>);
151    }
152</span></pre></code>
153<p>
154We pass the tupled args to all of our actors: cond, args and args appropriately. Notice how this expression reflects the C/C++ version almost to the letter.</p>
155<p>
156Well that's it. Now let's write a generator for this composite:</p>
157<code><pre>
158    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>&gt;
159    </span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>if_else_composite</span><span class=special>&lt;
160        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>CondT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>,
161        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>,
162        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>FalseT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>&gt; &gt;
163    </span><span class=identifier>if_else_</span><span class=special>(</span><span class=identifier>CondT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>cond</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>true_</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>false_</span><span class=special>)
164    {
165        </span><span class=keyword>typedef </span><span class=identifier>if_else_composite</span><span class=special>&lt;
166            </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>CondT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>,
167            </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>,
168            </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>FalseT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>&gt;
169        </span><span class=identifier>result</span><span class=special>;
170
171        </span><span class=keyword>return </span><span class=identifier>result</span><span class=special>(
172            </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>CondT</span><span class=special>&gt;::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>cond</span><span class=special>),
173            </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>&gt;::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>true_</span><span class=special>),
174            </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>FalseT</span><span class=special>&gt;::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>false_</span><span class=special>));
175    }
176</span></pre></code>
177<p>
178Now this should be trivial to explain. I hope. Again, let's digest this piecemeal.</p>
179<code><pre>
180    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>&gt;
181</span></pre></code>
182<p>
183Again, there are three elements involved: The CondT condition 'cond', the TrueT true branch 'true_, and the FalseT false branch 'false_'.</p>
184<code><pre>
185    <span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>if_else_composite</span><span class=special>&lt;
186        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>CondT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>,
187        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>,
188        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>FalseT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>&gt; &gt;
189</span></pre></code>
190<p>
191This is our target. We want to generate this actor. Now, given our arguments (cond, true_ and false_), we are not really sure if they are really actors. What if the user passes the boolean true as the cond? Surely, that has to be converted to an actor&lt;value&lt;bool&gt; &gt;, otherwise Phoenix will go berzerk and will not be able to accommodate this alien.</p>
192<code><pre>
193    <span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>T</span><span class=special>&gt;::</span><span class=identifier>type
194</span></pre></code>
195<p>
196is just what we need. This type computer converts from an arbitrary type T to a full-fledged actor citizen.</p>
197<code><pre>
198    <span class=identifier>if_else_</span><span class=special>(</span><span class=identifier>CondT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>cond</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>true_</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>false_</span><span class=special>)
199</span></pre></code>
200<p>
201These are the arguments to our generator 'if_else_'.</p>
202<code><pre>
203    <span class=keyword>typedef </span><span class=identifier>if_else_composite</span><span class=special>&lt;
204        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>CondT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>,
205        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>,
206        </span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>FalseT</span><span class=special>&gt;::</span><span class=identifier>type</span><span class=special>&gt;
207    </span><span class=identifier>result</span><span class=special>;
208</span></pre></code>
209<p>
210Same as before, this is our target return type, this time stripped off the actor. That's OK because the actor&lt;T&gt; has a constructor that takes in a BaseT object: 'result' in this case.</p>
211<code><pre>
212    <span class=keyword>return </span><span class=identifier>result</span><span class=special>(
213        </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>CondT</span><span class=special>&gt;::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>cond</span><span class=special>),
214        </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>&gt;::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>true_</span><span class=special>),
215        </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>FalseT</span><span class=special>&gt;::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>false_</span><span class=special>));
216</span></pre></code>
217<p>
218Finally, we construct and return our result. Notice how we called the as_actor&lt;T&gt;::convert static function to do the conversion from T to a full-fledged actor for each of the arguments.</p>
219<p>
220At last. Now we can use our brand new composite and its generator:</p>
221<code><pre>
222    <span class=comment>//  Print all contents of an STL container c and
223    //  prefix &quot; is odd&quot; or &quot; is even&quot; appropriately.
224
225    </span><span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
226        </span><span class=identifier>cout
227            </span><span class=special>&lt;&lt; </span><span class=identifier>arg1
228            </span><span class=special>&lt;&lt; </span><span class=identifier>if_else_</span><span class=special>(</span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>, </span><span class=string>&quot; is odd&quot;</span><span class=special>, </span><span class=string>&quot; is even&quot;</span><span class=special>)
229            &lt;&lt; </span><span class=identifier>val</span><span class=special>(</span><span class=literal>'\n'</span><span class=special>)
230    );
231</span></pre></code>
232<p>
2333)  Write an as_actor&lt;T&gt; converter for a specific type:</p>
234<p>
235By default, an unknown type T is converted to an actor&lt;value&lt;T&gt; &gt;. Say we just wrote a special primitive my_lazy_class following example 1. Whenever we have an object of type my_class, we want to convert this to a my_lazy_class automatically.</p>
236<p>
237as_actor&lt;T&gt; is Phoenix's type converter. All facilities that need to convert from an unknown type to an actor passes through this class. Specializing as_actor&lt;T&gt; for my_class is just what we need. For example:</p>
238<code><pre>
239    <span class=keyword>template </span><span class=special>&lt;&gt;
240    </span><span class=keyword>struct </span><span class=identifier>as_actor</span><span class=special>&lt;</span><span class=identifier>my_class</span><span class=special>&gt; {
241
242        </span><span class=keyword>typedef </span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>my_lazy_class</span><span class=special>&gt; </span><span class=identifier>type</span><span class=special>;
243        </span><span class=keyword>static </span><span class=identifier>type </span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>my_class </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>x</span><span class=special>)
244        { </span><span class=keyword>return </span><span class=identifier>my_lazy_class</span><span class=special>(</span><span class=identifier>x</span><span class=special>); }
245    };
246</span></pre></code>
247<p>
248For reference, here is the main is_actor&lt;T&gt; interface:</p>
249<code><pre>
250    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T</span><span class=special>&gt;
251    </span><span class=keyword>struct </span><span class=identifier>as_actor </span><span class=special>{
252
253        </span><span class=keyword>typedef </span><span class=special>??? </span><span class=identifier>type</span><span class=special>;
254        </span><span class=keyword>static </span><span class=identifier>type </span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>T </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>x</span><span class=special>);
255    };
256</span></pre></code>
257<p>
258where ??? is the actor type returned by the static convert function. By default, this is:</p>
259<code><pre>
260    <span class=keyword>typedef </span><span class=identifier>value</span><span class=special>&lt;</span><span class=identifier>T</span><span class=special>&gt; </span><span class=identifier>type</span><span class=special>;
261</span></pre></code>
262<p>
2634)  Write a specialized overloaded operator for a specific type:</p>
264<p>
265Consider the handling of operator &lt;&lt; std::ostream such as cout. When we see an expression such as:</p>
266<code><pre>
267    <span class=identifier>cout </span><span class=special>&lt;&lt; </span><span class=string>&quot;Hello World\n&quot;
268</span></pre></code>
269<p>
270the operator overload actually takes in cout by reference, modifies it and returns the same cout again by reference. This does not conform to the standard behavior of the shift left operator for built-in ints.</p>
271<p>
272In such cases, we can provide a specialized overload for this to work as a lazy-operator in expressions such as &quot;cout &lt;&lt; arg1 &lt;&lt; arg2;&quot; where the operatior behavior deviates from the standard operator:</p>
273<ol><li>std::ostream is taken as the LHS by reference</li><li>std::ostream is converted to an actor&lt;variable&lt;std::ostream&gt; &gt; instead of the default actor&lt;value&lt;std::ostream&gt; &gt;.</li></ol><p>
274We supply a special overload then (see special_ops.hpp):</p>
275<code><pre>
276    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>BaseT</span><span class=special>&gt;
277    </span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>composite</span><span class=special>&lt;
278        </span><span class=identifier>shift_l_op</span><span class=special>,                     //  </span><span class=identifier>an </span><span class=keyword>operator </span><span class=identifier>tag
279        </span><span class=identifier>variable</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>&gt;,         //  </span><span class=identifier>an </span><span class=identifier>actor </span><span class=identifier>LHS
280        </span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>BaseT</span><span class=special>&gt;,                   //  </span><span class=identifier>an </span><span class=identifier>actor </span><span class=identifier>RHS
281    </span><span class=special>&gt; &gt;
282    </span><span class=keyword>operator</span><span class=special>&lt;&lt;(
283        </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>&amp; </span><span class=identifier>_0</span><span class=special>,               //  </span><span class=identifier>LHS </span><span class=identifier>argument
284        </span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>BaseT</span><span class=special>&gt; </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>_1</span><span class=special>)         //  </span><span class=identifier>RHS </span><span class=identifier>argument
285    </span><span class=special>{
286        </span><span class=keyword>return </span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>composite</span><span class=special>&lt;
287            </span><span class=identifier>shift_l_op</span><span class=special>,                 //  </span><span class=identifier>an </span><span class=keyword>operator </span><span class=identifier>tag
288            </span><span class=identifier>variable</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>&gt;,     //  </span><span class=identifier>an </span><span class=identifier>actor </span><span class=identifier>LHS
289            </span><span class=identifier>actor</span><span class=special>&lt;</span><span class=identifier>BaseT</span><span class=special>&gt;,               //  </span><span class=identifier>an </span><span class=identifier>actor </span><span class=identifier>RHS
290        </span><span class=special>&gt; &gt;(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>_0</span><span class=special>), </span><span class=identifier>_1</span><span class=special>);               //  </span><span class=identifier>construct </span>#<span class=identifier>em
291    </span><span class=special>}
292</span></pre></code>
293<p>
294Take note that the std::ostream reference is converted to a actor&lt;variable&lt;std::ostream&gt; &gt; instead of the default actor&lt;value&lt;std::ostream&gt; &gt; which is not appropriate in this case.</p>
295<p>
296This is not yet complete. Take note also that a specialization for binary_operator also needs to be written (see no. 6).</p>
297<p>
2985)  Specialize a rank&lt;T&gt; for a specific type or group of types:</p>
299<p>
300Scenario: We have a set of more specialized numeric classes with higher precision than the built-in types. We have integer, floating and rational classes. All of the classes allow type promotions from the built-ins. These classes have all the pertinent operators implemented along with a couple of mixed type operators whenever appropriate. The operators conform to the canonical behavior of the built-in types. We want to enable Phoenix support for our numeric classes.</p>
301<p>
302Solution: Write rank specializations for our numeric types. This is trivial and straightforward:</p>
303<code><pre>
304    <span class=keyword>template </span><span class=special>&lt;&gt; </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special>&lt;</span><span class=identifier>integer</span><span class=special>&gt;    { </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>10000</span><span class=special>; };
305    </span><span class=keyword>template </span><span class=special>&lt;&gt; </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special>&lt;</span><span class=identifier>floating</span><span class=special>&gt;   { </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>10020</span><span class=special>; };
306    </span><span class=keyword>template </span><span class=special>&lt;&gt; </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special>&lt;</span><span class=identifier>rational</span><span class=special>&gt;   { </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>10030</span><span class=special>; };
307</span></pre></code>
308<p>
309Now, whenever there are mixed-type operations such as a + b where a is a primitive built-in int and b is our rational class, the correct promotion will be applied, and the result will be a rational. The type with the higher rank will win.</p>
310<p>
3116)  Specialize a unary_operator&lt;TagT, T&gt; or binary_operator&lt;TagT, T0, T1&gt; for a specific type:</p>
312<p>
313Scenario: We have a non-STL conforming iterator named my_iterator. Fortunately, its ++ operator works as expected. Unfortunately, when applying the dereference operator *p, it returns an object of type my_class but does not follow STL's convention that iterator classes have a typedef named reference.</p>
314<p>
315Solution, write a unary_operator specialization for our non- standard class:</p>
316<code><pre>
317    <span class=keyword>template </span><span class=special>&lt;&gt;
318    </span><span class=keyword>struct </span><span class=identifier>unary_operator</span><span class=special>&lt;</span><span class=identifier>dereference_op</span><span class=special>, </span><span class=identifier>my_iterator</span><span class=special>&gt; {
319
320        </span><span class=keyword>typedef </span><span class=identifier>my_class </span><span class=identifier>result_type</span><span class=special>;
321        </span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>my_iterator </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>iter</span><span class=special>)
322        { </span><span class=keyword>return </span><span class=special>*</span><span class=identifier>iter</span><span class=special>; }
323    };
324</span></pre></code>
325<p>
326Scenario: We have a legacy bigint implementation that we use for cryptography. The class design is totally brain-dead and disobeys all the rules. For example, its + operator is destructive and actually applies the += semantics for efficiency (yes, there are such brain-dead beasts!).</p>
327<p>
328Solution: write a binary_operator specialization for our non- standard class:</p>
329<code><pre>
330    <span class=keyword>template </span><span class=special>&lt;&gt;
331    </span><span class=keyword>struct </span><span class=identifier>binary_operator</span><span class=special>&lt;</span><span class=identifier>plus_op</span><span class=special>, </span><span class=identifier>bigint</span><span class=special>, </span><span class=identifier>bigint</span><span class=special>&gt; {
332
333        </span><span class=keyword>typedef </span><span class=identifier>bigint</span><span class=special>&amp; </span><span class=identifier>result_type</span><span class=special>;
334        </span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>bigint</span><span class=special>&amp; </span><span class=identifier>lhs</span><span class=special>, </span><span class=identifier>bigint </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>rhs</span><span class=special>)
335        { </span><span class=keyword>return </span><span class=identifier>lhs </span><span class=special>+ </span><span class=identifier>rhs</span><span class=special>; }
336    };
337</span></pre></code>
338<p>
339Going back to our example in no. 4, we also need to write a binary_operator&lt;TagT, T0, T1&gt; specialization for ostreams because the &lt;&lt; operator for ostreams deviate from the normal behavior.</p>
340<code><pre>
341    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>&gt;
342    </span><span class=keyword>struct </span><span class=identifier>binary_operator</span><span class=special>&lt;</span><span class=identifier>shift_l_op</span><span class=special>, </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&gt; {
343
344        </span><span class=keyword>typedef </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>&amp; </span><span class=identifier>result_type</span><span class=special>;
345        </span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>&amp; </span><span class=identifier>out</span><span class=special>, </span><span class=identifier>T1 </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>rhs</span><span class=special>)
346        { </span><span class=keyword>return </span><span class=identifier>out </span><span class=special>&lt;&lt; </span><span class=identifier>rhs</span><span class=special>; }
347    };
348</span></pre></code>
349<p>
3507) Simply write a lazy-function.</p>
351<p>
352Consider this:</p>
353<code><pre>
354    <span class=keyword>struct </span><span class=identifier>if_else_func </span><span class=special>{
355
356        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>&gt;
357        </span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
358
359            </span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>FalseT</span><span class=special>&gt;::</span><span class=identifier>type </span><span class=identifier>type</span><span class=special>;
360        };
361
362        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>&gt;
363        </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special>&lt;</span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>FalseT</span><span class=special>&gt;::</span><span class=identifier>type
364        </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>CondT </span><span class=identifier>cond</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>t</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>f</span><span class=special>) </span><span class=keyword>const
365        </span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>cond </span><span class=special>? </span><span class=identifier>t </span><span class=special>: </span><span class=identifier>f</span><span class=special>; }
366    };
367
368    </span><span class=identifier>function</span><span class=special>&lt;</span><span class=identifier>if_else_func</span><span class=special>&gt; </span><span class=identifier>if_else_</span><span class=special>;
369</span></pre></code>
370<p>
371And this corresponding usage:</p>
372<code><pre>
373    <span class=comment>//  Print all contents of an STL container c and
374    //  prefix &quot; is odd&quot; or &quot; is even&quot; appropriately.
375
376    </span><span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
377        </span><span class=identifier>cout
378            </span><span class=special>&lt;&lt; </span><span class=identifier>arg1
379            </span><span class=special>&lt;&lt; </span><span class=identifier>if_else_</span><span class=special>(</span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>, </span><span class=string>&quot; is odd&quot;</span><span class=special>, </span><span class=string>&quot; is even&quot;</span><span class=special>)
380            &lt;&lt; </span><span class=identifier>val</span><span class=special>(</span><span class=literal>'\n'</span><span class=special>)
381    );
382</span></pre></code>
383<p>
384What the $%^!? If we can do this, why on earth did we go to all the trouble twisting our brains inside out with the if_else_ composite in no. 2? Hey, not so fast, there's a slight difference that justifies the if_else_ composite: It is not apparent in the example, but the composite version of the if_else_ evaluates either the true or the false branch, **but not both**. The lazy-function version above always eagerly evaluates all its arguments before the function is called. Thus, if we are to adhere strongly to C/C++ semantics, we need the composite version.</p>
385<p>
386Besides, I need to show an example... Hmmm, so what's the point of no. 7 then? Well, in most cases, a lazy-function will suffice. These beasts are quite powerful, you know.</p>
387<table border="0">
388  <tr>
389    <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
390    <td width="30"><a href="operators_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
391    <td width="20"><a href="wrap_up.html"><img src="theme/r_arr.gif" border="0"></a></td>
392   </tr>
393</table>
394<br>
395<hr size="1">
396<p class="copyright">Copyright &copy; 2001-2002 Joel de Guzman<br>
397  <br>
398<font size="2">Use, modification and distribution is subject to the Boost Software
399    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
400    http://www.boost.org/LICENSE_1_0.txt) </font> </p>
401</body>
402</html>
Note: See TracBrowser for help on using the repository browser.