]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/mpl/doc/tutorial/implementing.html
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / mpl / doc / tutorial / implementing.html
1 <?xml version="1.0" encoding="utf-8" ?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4 <!-- Copyright Aleksey Gurtovoy 2006. Distributed under the Boost -->
5 <!-- Software License, Version 1.0. (See accompanying -->
6 <!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
7 <head>
8 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
9 <meta name="generator" content="Docutils 0.3.6: http://docutils.sourceforge.net/" />
10 <title>THE BOOST MPL LIBRARY: Implementing Multiplication</title>
11 <link rel="stylesheet" href="../style.css" type="text/css" />
12 </head>
13 <body class="docframe">
14 <table class="header"><tr class="header"><td class="header-group navigation-bar"><span class="navigation-group"><a href="./implementing-addition-and.html" class="navigation-link">Prev</a>&nbsp;<a href="./implementing-division.html" class="navigation-link">Next</a></span><span class="navigation-group-separator">&nbsp;|&nbsp;</span><span class="navigation-group"><a href="./implementing-addition-and.html" class="navigation-link">Back</a>&nbsp;<a href="./implementing-division.html" class="navigation-link">Along</a></span><span class="navigation-group-separator">&nbsp;|&nbsp;</span><span class="navigation-group"><a href="./dimensional-analysis.html" class="navigation-link">Up</a>&nbsp;<a href="../index.html" class="navigation-link">Home</a></span><span class="navigation-group-separator">&nbsp;|&nbsp;</span><span class="navigation-group"><a href="./tutorial_toc.html" class="navigation-link">Full TOC</a></span></td>
15 <td class="header-group page-location"><a href="../index.html" class="navigation-link">Front Page</a> / <a href="./tutorial-metafunctions.html" class="navigation-link">Tutorial: Metafunctions and Higher-Order Metaprogramming</a> / <a href="./dimensional-analysis.html" class="navigation-link">Dimensional Analysis</a> / <a href="./implementing.html" class="navigation-link">Implementing Multiplication</a></td>
16 </tr></table><div class="header-separator"></div>
17 <div class="section" id="implementing">
18 <h1><a class="toc-backref" href="./dimensional-analysis.html#id45" name="implementing">Implementing Multiplication</a></h1>
19 <p>Multiplication is a bit more complicated than addition and
20 subtraction. So far, the dimensions of the arguments and results have
21 all been identical, but when multiplying, the result will usually
22 have different dimensions from either of the arguments. For
23 multiplication, the relation:</p>
24 <blockquote>
25 (<em>x</em><sup>a</sup>)(<em>x</em><sup>b</sup>) == <em>x</em> <sup>(a + b)</sup></blockquote>
26 <!-- @litre_translator.line_offset -= 7 -->
27 <p>implies that the exponents of the result dimensions should be the
28 sum of corresponding exponents from the argument
29 dimensions. Division is similar, except that the sum is replaced by
30 a difference.</p>
31 <p>To combine corresponding elements from two sequences, we'll use
32 MPL's <tt class="literal"><span class="pre">transform</span></tt> algorithm. <tt class="literal"><span class="pre">transform</span></tt> is a metafunction
33 that iterates through two input sequences in parallel, passing an
34 element from each sequence to an arbitrary binary metafunction, and
35 placing the result in an output sequence.</p>
36 <pre class="literal-block">
37 template &lt;class Sequence1, class Sequence2, class BinaryOperation&gt;
38 struct transform; // returns a Sequence
39 </pre>
40 <p>The signature above should look familiar if you're acquainted with the
41 STL <tt class="literal"><span class="pre">transform</span></tt> algorithm that accepts two <em>runtime</em> sequences
42 as inputs:</p>
43 <pre class="literal-block">
44 template &lt;
45 class InputIterator1, class InputIterator2
46 , class OutputIterator, class BinaryOperation
47 &gt;
48 void transform(
49 InputIterator1 start1, InputIterator2 finish1
50 , InputIterator2 start2
51 , OutputIterator result, BinaryOperation func);
52 </pre>
53 <!-- @ example.wrap('namespace shield{','}')
54 compile() -->
55 <p>Now we just need to pass a <tt class="literal"><span class="pre">BinaryOperation</span></tt> that adds or
56 subtracts in order to multiply or divide dimensions with
57 <tt class="literal"><span class="pre">mpl::transform</span></tt>. If you look through the <a class="reference" href="./reference-manual.html">the MPL reference manual</a>, you'll
58 come across <tt class="literal"><span class="pre">plus</span></tt> and <tt class="literal"><span class="pre">minus</span></tt> metafunctions that do just what
59 you'd expect:</p>
60 <pre class="literal-block">
61 #include &lt;boost/static_assert.hpp&gt;
62 #include &lt;boost/mpl/plus.hpp&gt;
63 #include &lt;boost/mpl/int.hpp&gt;
64 namespace mpl = boost::mpl;
65
66 BOOST_STATIC_ASSERT((
67 mpl::plus&lt;
68 mpl::int_&lt;2&gt;
69 , mpl::int_&lt;3&gt;
70 &gt;::type::value == 5
71 ));
72 </pre>
73 <!-- @ compile(pop = None) -->
74 <div class="sidebar">
75 <p class="sidebar-title first"><tt class="literal"><span class="pre">BOOST_STATIC_ASSERT</span></tt></p>
76 <p>is a macro that causes a compilation error if its argument is
77 false. The double parentheses are required because the C++
78 preprocessor can't parse templates: it would otherwise be
79 fooled by the comma into treating the condition as two separate
80 macro arguments. Unlike its runtime analogue <tt class="literal"><span class="pre">assert(...)</span></tt>,
81 <tt class="literal"><span class="pre">BOOST_STATIC_ASSERT</span></tt> can also be used at class scope,
82 allowing us to put assertions in our metafunctions. See
83 Chapter <a class="reference" href="./resources.html">8</a> for an in-depth discussion.</p>
84 </div>
85 <!-- @prefix.append('#include <boost/static_assert.hpp>') -->
86 <p>At this point it might seem as though we have a solution, but we're
87 not quite there yet. A naive attempt to apply the <tt class="literal"><span class="pre">transform</span></tt>
88 algorithm in the implementation of <tt class="literal"><span class="pre">operator*</span></tt> yields a compiler
89 error:</p>
90 <pre class="literal-block">
91 #include &lt;boost/mpl/transform.hpp&gt;
92
93 template &lt;class T, class D1, class D2&gt;
94 quantity&lt;
95 T
96 , typename mpl::transform&lt;D1,D2,mpl::plus&gt;::type
97 &gt;
98 operator*(quantity&lt;T,D1&gt; x, quantity&lt;T,D2&gt; y) { ... }
99 </pre>
100 <!-- @ example.replace('{ ... }',';')
101 compile('all', pop = 1, expect_error = True)
102 prefix +=['#include <boost/mpl/transform.hpp>'] -->
103 <!-- @litre_translator.line_offset -= 7 -->
104 <p>It fails because the protocol says that metafunction arguments
105 must be types, and <tt class="literal"><span class="pre">plus</span></tt> is not a type, but a class template.
106 Somehow we need to make metafunctions like <tt class="literal"><span class="pre">plus</span></tt> fit the
107 metadata mold.</p>
108 <p>One natural way to introduce polymorphism between metafunctions and
109 metadata is to employ the wrapper idiom that gave us polymorphism
110 between types and integral constants. Instead of a nested integral
111 constant, we can use a class template nested within a
112 <strong>metafunction class</strong>:</p>
113 <pre class="literal-block">
114 struct plus_f
115 {
116 template &lt;class T1, class T2&gt;
117 struct apply
118 {
119 typedef typename mpl::plus&lt;T1,T2&gt;::type type;
120 };
121 };
122 </pre>
123 <div class="admonition-definition admonition">
124 <p class="admonition-title first">Definition</p>
125 <p>A <strong>Metafunction Class</strong> is a class with a publicly accessible
126 nested metafunction called <tt class="literal"><span class="pre">apply</span></tt>.</p>
127 </div>
128 <p>Whereas a metafunction is a template but not a type, a
129 metafunction class wraps that template within an ordinary
130 non-templated class, which <em>is</em> a type. Since metafunctions
131 operate on and return types, a metafunction class can be passed as
132 an argument to, or returned from, another metafunction.</p>
133 <p>Finally, we have a <tt class="literal"><span class="pre">BinaryOperation</span></tt> type that we can pass to
134 <tt class="literal"><span class="pre">transform</span></tt> without causing a compilation error:</p>
135 <pre class="literal-block">
136 template &lt;class T, class D1, class D2&gt;
137 quantity&lt;
138 T
139 , typename mpl::transform&lt;D1,D2,<strong>plus_f</strong>&gt;::type // new dimensions
140 &gt;
141 operator*(quantity&lt;T,D1&gt; x, quantity&lt;T,D2&gt; y)
142 {
143 typedef typename mpl::transform&lt;D1,D2,<strong>plus_f</strong>&gt;::type dim;
144 return quantity&lt;T,dim&gt;( x.value() * y.value() );
145 }
146 </pre>
147 <p>Now, if we want to compute the force exterted by gravity on a 5 kilogram
148 laptop computer, that's just the acceleration due to gravity (9.8
149 m/sec<sup>2</sup>) times the mass of the laptop:</p>
150 <pre class="literal-block">
151 quantity&lt;float,mass&gt; m(5.0f);
152 quantity&lt;float,acceleration&gt; a(9.8f);
153 std::cout &lt;&lt; &quot;force = &quot; &lt;&lt; (m * a).value();
154 </pre>
155 <!-- @example.wrap('#include <iostream>\nvoid ff() {', '}')
156
157 compile('all', pop = 1) -->
158 <p>Our <tt class="literal"><span class="pre">operator*</span></tt> multiplies the runtime values (resulting in
159 6.0f), and our metaprogram code uses <tt class="literal"><span class="pre">transform</span></tt> to sum the
160 meta-sequences of fundamental dimension exponents, so that the
161 result type contains a representation of a new list of exponents,
162 something like:</p>
163 <pre class="literal-block">
164 mpl::vector_c&lt;int,1,1,-2,0,0,0,0&gt;
165 </pre>
166 <!-- @example.wrap('''
167 #include <boost/mpl/vector_c.hpp>
168 typedef''', 'xxxx;')
169 compile() -->
170 <!-- @litre_translator.line_offset -= 7 -->
171 <p>However, if we try to write:</p>
172 <pre class="literal-block">
173 quantity&lt;float,force&gt; f = m * a;
174 </pre>
175 <!-- @ ma_function_args = '(quantity<float,mass> m, quantity<float,acceleration> a)'
176
177 example.wrap('void bogus%s {' % ma_function_args, '}')
178 compile('all', pop = 1, expect_error = True) -->
179 <!-- @litre_translator.line_offset -= 7 -->
180 <p>we'll run into a little problem. Although the result of
181 <tt class="literal"><span class="pre">m</span> <span class="pre">*</span> <span class="pre">a</span></tt> does indeed represent a force with exponents of mass,
182 length, and time 1, 1, and -2 respectively, the type returned by
183 <tt class="literal"><span class="pre">transform</span></tt> isn't a specialization of <tt class="literal"><span class="pre">vector_c</span></tt>. Instead,
184 <tt class="literal"><span class="pre">transform</span></tt> works generically on the elements of its inputs and
185 builds a new sequence with the appropriate elements: a type with
186 many of the same sequence properties as
187 <tt class="literal"><span class="pre">mpl::vector_c&lt;int,1,1,-2,0,0,0,0&gt;</span></tt>, but with a different C++ type
188 altogether. If you want to see the type's full name, you can try
189 to compile the example yourself and look at the error message, but
190 the exact details aren't important. The point is that
191 <tt class="literal"><span class="pre">force</span></tt> names a different type, so the assignment above will fail.</p>
192 <p>In order to resolve the problem, we can add an implicit conversion
193 from the multiplication's result type to <tt class="literal"><span class="pre">quantity&lt;float,force&gt;</span></tt>.
194 Since we can't predict the exact types of the dimensions involved
195 in any computation, this conversion will have to be templated,
196 something like:</p>
197 <pre class="literal-block">
198 template &lt;class T, class Dimensions&gt;
199 struct quantity
200 {
201 // converting constructor
202 template &lt;class OtherDimensions&gt;
203 quantity(quantity&lt;T,OtherDimensions&gt; const&amp; rhs)
204 : m_value(rhs.value())
205 {
206 }
207 ...
208 </pre>
209 <!-- @ example.append("""
210 explicit quantity(T x)
211 : m_value(x)
212 {}
213
214 T value() const { return m_value; }
215 private:
216 T m_value;
217 };""")
218
219 stack[quantity_declaration] = example
220 ignore() -->
221 <p>Unfortunately, such a general conversion undermines our whole
222 purpose, allowing nonsense such as:</p>
223 <pre class="literal-block">
224 // Should yield a force, not a mass!
225 quantity&lt;float,mass&gt; bogus = m * a;
226 </pre>
227 <!-- @ example.wrap('void bogus2%s {' % ma_function_args, '}')
228 bogus_example = example
229 compile('all', pop = 1) -->
230 <p>We can correct that problem using another MPL algorithm,
231 <tt class="literal"><span class="pre">equal</span></tt>, which tests that two sequences have the same elements:</p>
232 <pre class="literal-block">
233 template &lt;class OtherDimensions&gt;
234 quantity(quantity&lt;T,OtherDimensions&gt; const&amp; rhs)
235 : m_value(rhs.value())
236 {
237 BOOST_STATIC_ASSERT((
238 mpl::equal&lt;Dimensions,OtherDimensions&gt;::type::value
239 ));
240 }
241 </pre>
242 <!-- @ example.wrap('''
243 #include <boost/mpl/equal.hpp>
244
245 template <class T, class Dimensions>
246 struct quantity
247 {
248 explicit quantity(T x)
249 : m_value(x)
250 {}
251
252 T value() const { return m_value; }
253 ''','''
254 private:
255 T m_value;
256 };''')
257
258 stack[quantity_declaration] = example
259 stack[-1] = bogus_example
260 compile('all', pop = 1, expect_error = True) -->
261 <p>Now, if the dimensions of the two quantities fail to match, the
262 assertion will cause a compilation error.</p>
263 </div>
264
265 <div class="footer-separator"></div>
266 <table class="footer"><tr class="footer"><td class="header-group navigation-bar"><span class="navigation-group"><a href="./implementing-addition-and.html" class="navigation-link">Prev</a>&nbsp;<a href="./implementing-division.html" class="navigation-link">Next</a></span><span class="navigation-group-separator">&nbsp;|&nbsp;</span><span class="navigation-group"><a href="./implementing-addition-and.html" class="navigation-link">Back</a>&nbsp;<a href="./implementing-division.html" class="navigation-link">Along</a></span><span class="navigation-group-separator">&nbsp;|&nbsp;</span><span class="navigation-group"><a href="./dimensional-analysis.html" class="navigation-link">Up</a>&nbsp;<a href="../index.html" class="navigation-link">Home</a></span><span class="navigation-group-separator">&nbsp;|&nbsp;</span><span class="navigation-group"><a href="./tutorial_toc.html" class="navigation-link">Full TOC</a></span></td>
267 </tr></table></body>
268 </html>