• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<html>
2<head>
3<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
4<title>Operators revisited</title>
5<link rel="stylesheet" href="theme/style.css" type="text/css">
6<link rel="prev" href="composites_revisited.html">
7<link rel="next" href="interfacing.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>Operators revisited</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="composites_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
25    <td width="20"><a href="interfacing.html"><img src="theme/r_arr.gif" border="0"></a></td>
26   </tr>
27</table>
28<p>
29Each C++ operator has a special tag type associated with it. For example the binary + operator has a plus_op tag type associated with it. This operator tag is used to specialize either:</p>
30<ol><li>unary_operator&lt;TagT, T0&gt;</li><li>binary_operator&lt;TagT, T0, T1&gt;</li></ol><p>
31template classes (see unary_operator and binary_operator below). Specializations of these unary_operator and binary_operator are the actual workhorses that implement the operations. The behavior of each lazy operator depends on these unary_operator and binary_operator specializations.</p>
32<p>
33Preset specializations conform to the canonical operator rules modeled by the behavior of integers and pointers:</p>
34<ul><li>Prefix -, + and ~ accept constant arguments and return an object by value.</li><li>The ! accept constant arguments and returns a boolean result.</li><li>The &amp; (address-of), * (dereference) both return a reference to an object.</li><li>Prefix ++ returns a reference to its mutable argument after it is incremented.</li><li>Postfix ++ returns the mutable argument by value before it is incremented.</li><li>The += and its family accept mutable right hand side (rhs) operand and return a reference to the rhs operand.</li><li>Infix + and its family accept constant arguments and return an object by value.</li><li>The == and its family accept constant arguments and return a boolean result.</li><li>Operators &amp;&amp; and || accept constant arguments and return a boolean result and are short circuit evaluated as expected.</li></ul><a name="special_operators_and_extensibility"></a><h2>Special operators and extensibility</h2><p>
35It is of course possible to override the standard operator behavior when appropriate. For example, the behavior of std::cout does not conform to the canonocal shift left operator &lt;&lt; (i.e. the rhs std::cout is a mutable reference). Odd balls such as this are placed in special_ops.hpp. There you will find specializations for various classes found in the standard lib.</p>
36<p>
37The library is meant to be extensible. Users may implement their own specializations to allow other libraries to be adapted to be partial-function-evaluation savvy. Later on, in the section &quot;Interfacing (to applications, libraries and frameworks)&quot;, discussion will be focused on interfacing and extending the framework.</p>
38<a name="operator_tags"></a><h2>Operator tags</h2><p>
39Each C++ operator has a corresponding tag type. This is used as a means for specializing the unary_operator and binary_operator (see below). The tag also serves as the lazy operator type compatible with a composite as an operation (see composite). Here are two examples of operator tags:</p>
40<p>
41Unary example:</p>
42<code><pre>
43    <span class=keyword>struct </span><span class=identifier>negative_op </span><span class=special>{
44
45        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>&gt;
46        </span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
47
48            </span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>unary_operator</span><span class=special>&lt;</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>&gt;
49                ::</span><span class=identifier>result_type </span><span class=identifier>type</span><span class=special>;
50        };
51
52        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>&gt;
53        </span><span class=keyword>typename </span><span class=identifier>unary_operator</span><span class=special>&lt;</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>&gt;::</span><span class=identifier>result_type
54        </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>T0</span><span class=special>&amp; </span><span class=identifier>_0</span><span class=special>) </span><span class=keyword>const
55        </span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>unary_operator</span><span class=special>&lt;</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>&gt;::</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>_0</span><span class=special>); }
56    };
57</span></pre></code>
58<p>
59Binary example:</p>
60<code><pre>
61    <span class=keyword>struct </span><span class=identifier>plus_op </span><span class=special>{
62
63        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>&gt;
64        </span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
65
66            </span><span class=keyword>typedef </span><span class=keyword>typename </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>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&gt;
67                ::</span><span class=identifier>result_type </span><span class=identifier>type</span><span class=special>;
68        };
69
70        </span><span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>&gt;
71        </span><span class=keyword>typename </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>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&gt;::</span><span class=identifier>result_type
72        </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>T0</span><span class=special>&amp; </span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&amp; </span><span class=identifier>_1</span><span class=special>) </span><span class=keyword>const
73        </span><span class=special>{ </span><span class=keyword>return </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>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&gt;::</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>_1</span><span class=special>); }
74    };
75</span></pre></code>
76<p>
77Notice that these are again perfect examples of a composite operation. This style of specialized function is ubiquitous in the framework. We shall see how the unary_operator&lt;negative_op, T0&gt; and the binary_operator&lt;plus_op, T0, T1&gt; template classes, work in a short while.</p>
78<p>
79Here are the complete list of operator tags:</p>
80<code><pre>
81    <span class=comment>//  Unary operator tags
82
83    </span><span class=keyword>struct </span><span class=identifier>negative_op</span><span class=special>;         </span><span class=keyword>struct </span><span class=identifier>positive_op</span><span class=special>;
84    </span><span class=keyword>struct </span><span class=identifier>logical_not_op</span><span class=special>;      </span><span class=keyword>struct </span><span class=identifier>invert_op</span><span class=special>;
85    </span><span class=keyword>struct </span><span class=identifier>reference_op</span><span class=special>;        </span><span class=keyword>struct </span><span class=identifier>dereference_op</span><span class=special>;
86    </span><span class=keyword>struct </span><span class=identifier>pre_incr_op</span><span class=special>;         </span><span class=keyword>struct </span><span class=identifier>pre_decr_op</span><span class=special>;
87    </span><span class=keyword>struct </span><span class=identifier>post_incr_op</span><span class=special>;        </span><span class=keyword>struct </span><span class=identifier>post_decr_op</span><span class=special>;
88
89    //  </span><span class=identifier>Binary </span><span class=keyword>operator </span><span class=identifier>tags
90
91    </span><span class=keyword>struct </span><span class=identifier>assign_op</span><span class=special>;           </span><span class=keyword>struct </span><span class=identifier>index_op</span><span class=special>;
92    </span><span class=keyword>struct </span><span class=identifier>plus_assign_op</span><span class=special>;      </span><span class=keyword>struct </span><span class=identifier>minus_assign_op</span><span class=special>;
93    </span><span class=keyword>struct </span><span class=identifier>times_assign_op</span><span class=special>;     </span><span class=keyword>struct </span><span class=identifier>divide_assign_op</span><span class=special>;    </span><span class=keyword>struct </span><span class=identifier>mod_assign_op</span><span class=special>;
94    </span><span class=keyword>struct </span><span class=identifier>and_assign_op</span><span class=special>;       </span><span class=keyword>struct </span><span class=identifier>or_assign_op</span><span class=special>;        </span><span class=keyword>struct </span><span class=identifier>xor_assign_op</span><span class=special>;
95    </span><span class=keyword>struct </span><span class=identifier>shift_l_assign_op</span><span class=special>;   </span><span class=keyword>struct </span><span class=identifier>shift_r_assign_op</span><span class=special>;
96
97    </span><span class=keyword>struct </span><span class=identifier>plus_op</span><span class=special>;             </span><span class=keyword>struct </span><span class=identifier>minus_op</span><span class=special>;
98    </span><span class=keyword>struct </span><span class=identifier>times_op</span><span class=special>;            </span><span class=keyword>struct </span><span class=identifier>divide_op</span><span class=special>;           </span><span class=keyword>struct </span><span class=identifier>mod_op</span><span class=special>;
99    </span><span class=keyword>struct </span><span class=identifier>and_op</span><span class=special>;              </span><span class=keyword>struct </span><span class=identifier>or_op</span><span class=special>;               </span><span class=keyword>struct </span><span class=identifier>xor_op</span><span class=special>;
100    </span><span class=keyword>struct </span><span class=identifier>shift_l_op</span><span class=special>;          </span><span class=keyword>struct </span><span class=identifier>shift_r_op</span><span class=special>;
101
102    </span><span class=keyword>struct </span><span class=identifier>eq_op</span><span class=special>;               </span><span class=keyword>struct </span><span class=identifier>not_eq_op</span><span class=special>;
103    </span><span class=keyword>struct </span><span class=identifier>lt_op</span><span class=special>;               </span><span class=keyword>struct </span><span class=identifier>lt_eq_op</span><span class=special>;
104    </span><span class=keyword>struct </span><span class=identifier>gt_op</span><span class=special>;               </span><span class=keyword>struct </span><span class=identifier>gt_eq_op</span><span class=special>;
105    </span><span class=keyword>struct </span><span class=identifier>logical_and_op</span><span class=special>;      </span><span class=keyword>struct </span><span class=identifier>logical_or_op</span><span class=special>;
106</span></pre></code>
107<a name="unary_operator"></a><h3>unary_operator</h3><p>
108The unary_operator class implements most of the C++ unary operators. Each specialization is basically a simple static eval function plus a result_type typedef that determines the return type of the eval function.</p>
109<p>
110TagT is one of the unary operator tags above and T is the data type (argument) involved in the operation. Here is an example:</p>
111<code><pre>
112    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T</span><span class=special>&gt;
113    </span><span class=keyword>struct </span><span class=identifier>unary_operator</span><span class=special>&lt;</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T</span><span class=special>&gt; {
114
115        </span><span class=keyword>typedef </span><span class=identifier>T </span><span class=keyword>const </span><span class=identifier>result_type</span><span class=special>;
116        </span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>T </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>v</span><span class=special>)
117        { </span><span class=keyword>return </span><span class=special>-</span><span class=identifier>v</span><span class=special>; }
118    };
119</span></pre></code>
120<p>
121This example is exactly what was being referred to by the first example we saw in the section on operator tags.</p>
122<p>
123Only the behavior of C/C++ built-in types are taken into account in the specializations provided in operator.hpp. For user-defined types, these specializations may still be used provided that the operator overloads of such types adhere to the standard behavior of built-in types.</p>
124<p>
125A separate special_ops.hpp file implements more STL savvy specializations. Other more specialized unary_operator implementations may be defined by the client for specific unary operator tags/data types.</p>
126<a name="binary_operator"></a><h3>binary_operator</h3><p>
127The binary_operator class implements most of the C++ binary operators. Each specialization is basically a simple static eval function plus a result_type typedef that determines the return type of the eval function.</p>
128<p>
129TagT is one of the binary operator tags above T0 and T1 are the (arguments') data types involved in the operation. Here is an example:</p>
130<code><pre>
131    <span class=keyword>template </span><span class=special>&lt;</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>&gt;
132    </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>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&gt; {
133
134        </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>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&gt;::</span><span class=identifier>type </span><span class=keyword>const </span><span class=identifier>result_type</span><span class=special>;
135        </span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>T0 </span><span class=keyword>const</span><span class=special>&amp; </span><span class=identifier>lhs</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>)
136        { </span><span class=keyword>return </span><span class=identifier>lhs </span><span class=special>+ </span><span class=identifier>rhs</span><span class=special>; }
137    };
138</span></pre></code>
139<p>
140This example is exactly what was being referred to by the second example we saw in the section on operator tags. higher_rank&lt;T0, T1&gt; is a type computer. We shall see how this works in a short while, pardon the forward information.</p>
141<p>
142Only the behavior of C/C++ built-in types are taken into account in the specializations provided in operator.hpp. For user-defined types, these specializations may still be used provided that the operator overloads of such types adhere to the standard behavior of built-in types.</p>
143<p>
144A separate special_ops.hpp file implements more STL savvy specializations. Other more specialized unary_operator implementations may be defined by the client for specific unary operator tags/data types.</p>
145<p>
146All binary_operator except the logical_and_op and logical_or_op have an eval static function that carries out the actual operation. The logical_and_op and logical_or_op d are special because these two operators are short-circuit evaluated.</p>
147<table width="80%" border="0" align="center">
148  <tr>
149    <td class="note_box">
150<img src="theme/lens.gif"></img> <b>Short Circuiting || and &amp;&amp;</b><br><br>The logical_and_op and logical_or_op are special due to the C/C++ short circuiting rule, i.e. a || b and a &amp;&amp; b are short circuit evaluated. A forwarding operation cannot be used because all function arguments are evaluated before a function is called. logical_and_op and logical_or_op are specialized composites with implied operations.    </td>
151  </tr>
152</table>
153<a name="rank"></a><h2>rank</h2><p>
154rank&lt;T&gt; class has a static int constant 'value' that defines the absolute rank of a type. rank&lt;T&gt; is used to choose the result type of binary operators such as +. The type with the higher rank wins and is used as the operator's return type. A generic user defined type has a very high rank and always wins when compared against a user defined type. If this is not desireable, one can write a rank specialization for the type. Here are some predefined examples:</p>
155<code><pre>
156    <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=keyword>char</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>20</span><span class=special>; };
157    </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=keyword>signed </span><span class=keyword>char</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>20</span><span class=special>; };
158    </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=keyword>unsigned </span><span class=keyword>char</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>30</span><span class=special>; };
159    </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=keyword>wchar_t</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>40</span><span class=special>; };
160</span></pre></code>
161<p>
162Take note that ranks 0..9999 are reserved by the framework.</p>
163<p>
164A template type computer higher_rank&lt;T0, T1&gt; chooses the type (T0 or T1) with the higher rank. We saw in the binary_operator for plus_op how it was used. Specifically:</p>
165<code><pre>
166    <span class=identifier>higher_rank</span><span class=special>&lt;</span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>&gt;::</span><span class=identifier>type
167</span></pre></code>
168<p>
169returns either T0 or T1 depending on which has a higher rank. In some operator applications such as a + b, the result is actually the one with the higher rank. For example if a is of type int and b is of type double, the result will be of type double. This facility can also be quite useful for evaluating some functions. For instance if we have a sum(a, b, c, d, e) function, we can call this type computer to get the type with the highest rank:</p>
170<code><pre>
171    <span class=identifier>higher_rank</span><span class=special>&lt;</span><span class=identifier>TA</span><span class=special>,
172        </span><span class=identifier>higher_rank</span><span class=special>&lt;</span><span class=identifier>TB</span><span class=special>,
173            </span><span class=identifier>higher_rank</span><span class=special>&lt;</span><span class=identifier>TC</span><span class=special>,
174                </span><span class=identifier>higher_rank</span><span class=special>&lt;</span><span class=identifier>TD</span><span class=special>, </span><span class=identifier>TE</span><span class=special>&gt;::</span><span class=identifier>type
175            </span><span class=special>&gt;::</span><span class=identifier>type
176        </span><span class=special>&gt;::</span><span class=identifier>type
177    </span><span class=special>&gt;::</span><span class=identifier>type
178</span></pre></code>
179<table width="80%" border="0" align="center">
180  <tr>
181    <td class="note_box">
182<img src="theme/alert.gif"></img> When used within templates, be sure to use 'typename' appropriately. See binary_operator&lt;plus_op, T0, T1&gt; above.    </td>
183  </tr>
184</table>
185<table border="0">
186  <tr>
187    <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
188    <td width="30"><a href="composites_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
189    <td width="20"><a href="interfacing.html"><img src="theme/r_arr.gif" border="0"></a></td>
190   </tr>
191</table>
192<br>
193<hr size="1">
194<p class="copyright">Copyright &copy; 2001-2002 Joel de Guzman<br>
195  <br>
196<font size="2">Use, modification and distribution is subject to the Boost Software
197    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
198    http://www.boost.org/LICENSE_1_0.txt) </font> </p>
199</body>
200</html>
201