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<TagT, T0></li><li>binary_operator<TagT, T0, T1></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 & (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 && 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 << (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 "Interfacing (to applications, libraries and frameworks)", 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><</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>> 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><</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>> 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><</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>> 53 </span><span class=keyword>typename </span><span class=identifier>unary_operator</span><span class=special><</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>>::</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>& </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><</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>>::</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><</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>> 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><</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>> 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><</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>> 71 </span><span class=keyword>typename </span><span class=identifier>binary_operator</span><span class=special><</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>>::</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>& </span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>& </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><</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>>::</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<negative_op, T0> and the binary_operator<plus_op, T0, T1> 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><</span><span class=keyword>typename </span><span class=identifier>T</span><span class=special>> 113 </span><span class=keyword>struct </span><span class=identifier>unary_operator</span><span class=special><</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T</span><span class=special>> { 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>& </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><</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>> 132 </span><span class=keyword>struct </span><span class=identifier>binary_operator</span><span class=special><</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>> { 133 134 </span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>>::</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>& </span><span class=identifier>lhs</span><span class=special>, </span><span class=identifier>T1 </span><span class=keyword>const</span><span class=special>& </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<T0, T1> 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 &&</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 && 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<T> class has a static int constant 'value' that defines the absolute rank of a type. rank<T> 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><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=keyword>char</span><span class=special>> { </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><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=keyword>signed </span><span class=keyword>char</span><span class=special>> { </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><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=keyword>unsigned </span><span class=keyword>char</span><span class=special>> { </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><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=keyword>wchar_t</span><span class=special>> { </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<T0, T1> 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><</span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>>::</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><</span><span class=identifier>TA</span><span class=special>, 172 </span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TB</span><span class=special>, 173 </span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TC</span><span class=special>, 174 </span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TD</span><span class=special>, </span><span class=identifier>TE</span><span class=special>>::</span><span class=identifier>type 175 </span><span class=special>>::</span><span class=identifier>type 176 </span><span class=special>>::</span><span class=identifier>type 177 </span><span class=special>>::</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<plus_op, T0, T1> 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 © 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