]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/classic/phoenix/doc/interfacing.html
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / spirit / classic / phoenix / doc / interfacing.html
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>
29 The 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">
30 Spirit</a> inline parser framework.</p>
31 <p>
32 Extension 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>
34 1) Write and deploy a new primitive:</p>
35 <p>
36 So 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 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>
49 That'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>
59 Now 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>
64 Prints 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>
69 2) Write and deploy a new composite:</p>
70 <p>
71 This 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>
73 Ok, 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>
104 Ok, 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>
110 This 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>
115 self_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>
127 We 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>
129 So 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>
131 Knowing 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>
133 Following 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>
140 This 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>
147 Now, 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>
154 We 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>
156 Well 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>
178 Now 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>
183 Again, 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>
191 This 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>
196 is 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>
201 These 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>
210 Same 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>
218 Finally, 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>
220 At 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>
233 3) Write an as_actor&lt;T&gt; converter for a specific type:</p>
234 <p>
235 By 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>
237 as_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>
248 For 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>
258 where ??? 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>
263 4) Write a specialized overloaded operator for a specific type:</p>
264 <p>
265 Consider 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>
270 the 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>
272 In 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>
274 We 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>
294 Take 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>
296 This is not yet complete. Take note also that a specialization for binary_operator also needs to be written (see no. 6).</p>
297 <p>
298 5) Specialize a rank&lt;T&gt; for a specific type or group of types:</p>
299 <p>
300 Scenario: 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>
302 Solution: 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>
309 Now, 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>
311 6) Specialize a unary_operator&lt;TagT, T&gt; or binary_operator&lt;TagT, T0, T1&gt; for a specific type:</p>
312 <p>
313 Scenario: 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>
315 Solution, 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>
326 Scenario: 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>
328 Solution: 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>
339 Going 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>
350 7) Simply write a lazy-function.</p>
351 <p>
352 Consider 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>
371 And 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>
384 What 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>
386 Besides, 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>