Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/doc/html/variant/tutorial.html @ 66

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

updated boost from 1_33_1 to 1_34_1

File size: 32.4 KB
Line 
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
4<title>Tutorial</title>
5<link rel="stylesheet" href="../boostbook.css" type="text/css">
6<meta name="generator" content="DocBook XSL Stylesheets V1.68.1">
7<link rel="start" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset">
8<link rel="up" href="../variant.html" title="Chapter 20. Boost.Variant">
9<link rel="prev" href="../variant.html" title="Chapter 20. Boost.Variant">
10<link rel="next" href="reference.html" title="Reference">
11</head>
12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13<table cellpadding="2" width="100%">
14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td>
15<td align="center"><a href="../../../index.htm">Home</a></td>
16<td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td>
17<td align="center"><a href="../../../people/people.htm">People</a></td>
18<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
19<td align="center"><a href="../../../more/index.htm">More</a></td>
20</table>
21<hr>
22<div class="spirit-nav">
23<a accesskey="p" href="../variant.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../variant.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="reference.html"><img src="../images/next.png" alt="Next"></a>
24</div>
25<div class="section" lang="en">
26<div class="titlepage"><div><div><h2 class="title" style="clear: both">
27<a name="variant.tutorial"></a>Tutorial</h2></div></div></div>
28<div class="toc"><dl>
29<dt><span class="section"><a href="tutorial.html#variant.tutorial.basic">Basic Usage</a></span></dt>
30<dt><span class="section"><a href="tutorial.html#variant.tutorial.advanced">Advanced Topics</a></span></dt>
31</dl></div>
32<div class="section" lang="en">
33<div class="titlepage"><div><div><h3 class="title">
34<a name="variant.tutorial.basic"></a>Basic Usage</h3></div></div></div>
35<p>A discriminated union container on some set of types is defined by
36  instantiating the <code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code> class
37  template with the desired types. These types are called
38  <span class="bold"><strong>bounded types</strong></span> and are subject to the
39  requirements of the
40  <a href="reference.html#variant.concepts.bounded-type" title="BoundedType"><span class="emphasis"><em>BoundedType</em></span></a>
41  concept. Any number of bounded types may be specified, up to some
42  implementation-defined limit (see
43  <code class="computeroutput"><a href="../BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES">BOOST_VARIANT_LIMIT_TYPES</a></code>).</p>
44<p>For example, the following declares a discriminated union container on
45  <code class="computeroutput">int</code> and <code class="computeroutput">std::string</code>:
46
47</p>
48<pre class="programlisting"><code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt; int, std::string &gt; v;</pre>
49<p>
50
51</p>
52<p>By default, a <code class="computeroutput">variant</code> default-constructs its first
53  bounded type, so <code class="computeroutput">v</code> initially contains <code class="computeroutput">int(0)</code>. If
54  this is not desired, or if the first bounded type is not
55  default-constructible, a <code class="computeroutput">variant</code> can be constructed
56  directly from any value convertible to one of its bounded types. Similarly,
57  a <code class="computeroutput">variant</code> can be assigned any value convertible to one of its
58  bounded types, as demonstrated in the following:
59
60</p>
61<pre class="programlisting">v = "hello";</pre>
62<p>
63
64</p>
65<p>Now <code class="computeroutput">v</code> contains a <code class="computeroutput">std::string</code> equal to
66  <code class="computeroutput">"hello"</code>. We can demonstrate this by
67  <span class="bold"><strong>streaming</strong></span> <code class="computeroutput">v</code> to standard
68  output:
69
70</p>
71<pre class="programlisting">std::cout &lt;&lt; v &lt;&lt; std::endl;</pre>
72<p>
73
74</p>
75<p>Usually though, we would like to do more with the content of a
76  <code class="computeroutput">variant</code> than streaming. Thus, we need some way to access the
77  contained value. There are two ways to accomplish this:
78  <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">apply_visitor</a></code>, which is safest
79  and very powerful, and
80  <code class="computeroutput"><a href="../boost/get.html" title="Function get">get</a>&lt;T&gt;</code>, which is
81  sometimes more convenient to use.</p>
82<p>For instance, suppose we wanted to concatenate to the string contained
83  in <code class="computeroutput">v</code>. With <span class="bold"><strong>value retrieval</strong></span>
84  by <code class="computeroutput"><a href="../boost/get.html" title="Function get">get</a></code>, this may be accomplished
85  quite simply, as seen in the following:
86
87</p>
88<pre class="programlisting">std::string&amp; str = <code class="computeroutput"><a href="../boost/get.html" title="Function get">boost::get</a></code>&lt;std::string&gt;(v);
89str += " world! ";</pre>
90<p>
91
92</p>
93<p>As desired, the <code class="computeroutput">std::string</code> contained by <code class="computeroutput">v</code> now
94  is equal to <code class="computeroutput">"hello world! "</code>. Again, we can demonstrate this by
95  streaming <code class="computeroutput">v</code> to standard output:
96
97</p>
98<pre class="programlisting">std::cout &lt;&lt; v &lt;&lt; std::endl;</pre>
99<p>
100
101</p>
102<p>While use of <code class="computeroutput">get</code> is perfectly acceptable in this trivial
103  example, <code class="computeroutput">get</code> generally suffers from several significant
104  shortcomings. For instance, if we were to write a function accepting a
105  <code class="computeroutput">variant&lt;int, std::string&gt;</code>, we would not know whether
106  the passed <code class="computeroutput">variant</code> contained an <code class="computeroutput">int</code> or a
107  <code class="computeroutput">std::string</code>. If we insisted upon continued use of
108  <code class="computeroutput">get</code>, we would need to query the <code class="computeroutput">variant</code> for its
109  contained type. The following function, which "doubles" the
110  content of the given <code class="computeroutput">variant</code>, demonstrates this approach:
111
112</p>
113<pre class="programlisting">void times_two( boost::variant&lt; int, std::string &gt; &amp; operand )
114{
115    if ( int* pi = <code class="computeroutput"><a href="../boost/get.html" title="Function get">boost::get</a></code>&lt;int&gt;( &amp;v ) )
116        *pi *= 2;
117    else if ( std::string* pstr = <code class="computeroutput"><a href="../boost/get.html" title="Function get">boost::get</a></code>&lt;std::string&gt;( &amp;v ) )
118        *pstr += *pstr;
119}</pre>
120<p>
121
122</p>
123<p>However, such code is quite brittle, and without careful attention will
124  likely lead to the introduction of subtle logical errors detectable only at
125  runtime. For instance, consider if we wished to extend
126  <code class="computeroutput">times_two</code> to operate on a <code class="computeroutput">variant</code> with additional
127  bounded types. Specifically, let's add
128  <code class="computeroutput">std::complex&lt;double&gt;</code> to the set. Clearly, we would need
129  to at least change the function declaration:
130
131</p>
132<pre class="programlisting">void times_two( boost::variant&lt; int, std::string, std::complex&lt;double&gt; &gt; &amp; operand )
133{
134    // as above...?
135}</pre>
136<p>
137
138</p>
139<p>Of course, additional changes are required, for currently if the passed
140  <code class="computeroutput">variant</code> in fact contained a <code class="computeroutput">std::complex</code> value,
141  <code class="computeroutput">times_two</code> would silently return -- without any of the desired
142  side-effects and without any error. In this case, the fix is obvious. But in
143  more complicated programs, it could take considerable time to identify and
144  locate the error in the first place.</p>
145<p>Thus, real-world use of <code class="computeroutput">variant</code> typically demands an access
146  mechanism more robust than <code class="computeroutput">get</code>. For this reason,
147  <code class="computeroutput">variant</code> supports compile-time checked
148  <span class="bold"><strong>visitation</strong></span> via
149  <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">apply_visitor</a></code>. Visitation requires
150  that the programmer explicitly handle (or ignore) each bounded type. Failure
151  to do so results in a compile-time error.</p>
152<p>Visitation of a <code class="computeroutput">variant</code> requires a visitor object. The
153  following demonstrates one such implementation of a visitor implementating
154  behavior identical to <code class="computeroutput">times_two</code>:
155
156</p>
157<pre class="programlisting">class times_two_visitor
158    : public <code class="computeroutput"><a href="../boost/static_visitor.html" title="Class template static_visitor">boost::static_visitor</a></code>&lt;&gt;
159{
160public:
161
162    void operator()(int &amp; i) const
163    {
164        i *= 2;
165    }
166
167    void operator()(std::string &amp; str) const
168    {
169        str += str;
170    }
171
172};</pre>
173<p>
174
175</p>
176<p>With the implementation of the above visitor, we can then apply it to
177  <code class="computeroutput">v</code>, as seen in the following:
178
179</p>
180<pre class="programlisting"><code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>( times_two_visitor(), v );</pre>
181<p>
182
183</p>
184<p>As expected, the content of <code class="computeroutput">v</code> is now a
185  <code class="computeroutput">std::string</code> equal to <code class="computeroutput">"hello world! hello world! "</code>.
186  (We'll skip the verification this time.)</p>
187<p>In addition to enhanced robustness, visitation provides another
188  important advantage over <code class="computeroutput">get</code>: the ability to write generic
189  visitors. For instance, the following visitor will "double" the
190  content of <span class="emphasis"><em>any</em></span> <code class="computeroutput">variant</code> (provided its
191  bounded types each support operator+=):
192
193</p>
194<pre class="programlisting">class times_two_generic
195    : public <code class="computeroutput"><a href="../boost/static_visitor.html" title="Class template static_visitor">boost::static_visitor</a></code>&lt;&gt;
196{
197public:
198
199    template &lt;typename T&gt;
200    void operator()( T &amp; operand ) const
201    {
202        operand += operand;
203    }
204
205};</pre>
206<p>
207
208</p>
209<p>Again, <code class="computeroutput">apply_visitor</code> sets the wheels in motion:
210
211</p>
212<pre class="programlisting"><code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>( times_two_generic(), v );</pre>
213<p>
214
215</p>
216<p>While the initial setup costs of visitation may exceed that required for
217  <code class="computeroutput">get</code>, the benefits quickly become significant. Before concluding
218  this section, we should explore one last benefit of visitation with
219  <code class="computeroutput">apply_visitor</code>:
220  <span class="bold"><strong>delayed visitation</strong></span>. Namely, a special form
221  of <code class="computeroutput">apply_visitor</code> is available that does not immediately apply
222  the given visitor to any <code class="computeroutput">variant</code> but rather returns a function
223  object that operates on any <code class="computeroutput">variant</code> given to it. This behavior
224  is particularly useful when operating on sequences of <code class="computeroutput">variant</code>
225  type, as the following demonstrates:
226
227</p>
228<pre class="programlisting">std::vector&lt; <code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt;int, std::string&gt; &gt; vec;
229vec.push_back( 21 );
230vec.push_back( "hello " );
231
232times_two_generic visitor;
233std::for_each(
234      vec.begin(), vec.end()
235   , <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>(visitor)
236   );</pre>
237<p>
238
239</p>
240</div>
241<div class="section" lang="en">
242<div class="titlepage"><div><div><h3 class="title">
243<a name="variant.tutorial.advanced"></a>Advanced Topics</h3></div></div></div>
244<div class="toc"><dl>
245<dt><span class="section"><a href="tutorial.html#variant.tutorial.preprocessor">Preprocessor macros</a></span></dt>
246<dt><span class="section"><a href="tutorial.html#variant.tutorial.over-sequence">Using a type sequence to specify bounded types</a></span></dt>
247<dt><span class="section"><a href="tutorial.html#variant.tutorial.recursive">Recursive <code class="computeroutput">variant</code> types</a></span></dt>
248<dt><span class="section"><a href="tutorial.html#variant.tutorial.binary-visitation">Binary visitation</a></span></dt>
249</dl></div>
250<p>This section discusses several features of the library often required
251  for advanced uses of <code class="computeroutput">variant</code>. Unlike in the above section, each
252  feature presented below is largely independent of the others. Accordingly,
253  this section is not necessarily intended to be read linearly or in its
254  entirety.</p>
255<div class="section" lang="en">
256<div class="titlepage"><div><div><h4 class="title">
257<a name="variant.tutorial.preprocessor"></a>Preprocessor macros</h4></div></div></div>
258<p>While the <code class="computeroutput">variant</code> class template's variadic parameter
259    list greatly simplifies use for specific instantiations of the template,
260    it significantly complicates use for generic instantiations. For instance,
261    while it is immediately clear how one might write a function accepting a
262    specific <code class="computeroutput">variant</code> instantiation, say
263    <code class="computeroutput">variant&lt;int, std::string&gt;</code>, it is less clear how one
264    might write a function accepting any given <code class="computeroutput">variant</code>.</p>
265<p>Due to the lack of support for true variadic template parameter lists
266    in the C++98 standard, the preprocessor is needed. While the
267    <a href="../../../libs/preprocessor/index.html" target="_top">Preprocessor</a> library provides a general and
268    powerful solution, the need to repeat
269    <code class="computeroutput"><a href="../BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES">BOOST_VARIANT_LIMIT_TYPES</a></code>
270    unnecessarily clutters otherwise simple code. Therefore, for common
271    use-cases, this library provides its own macro
272    <code class="computeroutput"><span class="bold"><strong><a href="../BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a></strong></span></code>.</p>
273<p>This macro simplifies for the user the process of declaring
274    <code class="computeroutput">variant</code> types in function templates or explicit partial
275    specializations of class templates, as shown in the following:
276
277</p>
278<pre class="programlisting">// general cases
279template &lt;typename T&gt; void some_func(const T &amp;);
280template &lt;typename T&gt; class some_class;
281
282// function template overload
283template &lt;<code class="computeroutput"><a href="../BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a></code>(typename T)&gt;
284void some_func(const <code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt;<code class="computeroutput"><a href="../BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a></code>(T)&gt; &amp;);
285
286// explicit partial specialization
287template &lt;<code class="computeroutput"><a href="../BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a></code>(typename T)&gt;
288class some_class&lt; <code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt;<code class="computeroutput"><a href="../BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a></code>(T)&gt; &gt;;</pre>
289<p>
290
291  </p>
292</div>
293<div class="section" lang="en">
294<div class="titlepage"><div><div><h4 class="title">
295<a name="variant.tutorial.over-sequence"></a>Using a type sequence to specify bounded types</h4></div></div></div>
296<p>While convenient for typical uses, the <code class="computeroutput">variant</code> class
297    template's variadic template parameter list is limiting in two significant
298    dimensions. First, due to the lack of support for true variadic template
299    parameter lists in C++, the number of parameters must be limited to some
300    implementation-defined maximum (namely,
301    <code class="computeroutput"><a href="../BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES">BOOST_VARIANT_LIMIT_TYPES</a></code>).
302    Second, the nature of parameter lists in general makes compile-time
303    manipulation of the lists excessively difficult.</p>
304<p>To solve these problems,
305    <code class="computeroutput">make_variant_over&lt; <span class="emphasis"><em>Sequence</em></span> &gt;</code>
306    exposes a <code class="computeroutput">variant</code> whose bounded types are the elements of
307    <code class="computeroutput">Sequence</code> (where <code class="computeroutput">Sequence</code> is any type fulfilling
308    the requirements of <a href="../../../libs/mpl/index.html" target="_top">MPL</a>'s
309    <span class="emphasis"><em>Sequence</em></span> concept). For instance,
310
311</p>
312<pre class="programlisting">typedef <code class="computeroutput">mpl::vector</code>&lt; std::string &gt; types_initial;
313typedef <code class="computeroutput">mpl::push_front</code>&lt; types_initial, int &gt;::type types;
314
315<code class="computeroutput"><a href="../boost/make_variant_over.html" title="Class template make_variant_over">boost::make_variant_over</a></code>&lt; types &gt;::type v1;</pre>
316<p>
317
318    behaves equivalently to
319
320</p>
321<pre class="programlisting"><code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt; int, std::string &gt; v2;</pre>
322<p>
323
324  </p>
325<p><span class="bold"><strong>Portability</strong></span>: Unfortunately, due to
326    standard conformance issues in several compilers,
327    <code class="computeroutput">make_variant_over</code> is not universally available. On these
328    compilers the library indicates its lack of support for the syntax via the
329    definition of the preprocessor symbol
330    <code class="computeroutput"><a href="../BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT.html" title="Macro BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT">BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT</a></code>.</p>
331</div>
332<div class="section" lang="en">
333<div class="titlepage"><div><div><h4 class="title">
334<a name="variant.tutorial.recursive"></a>Recursive <code class="computeroutput">variant</code> types</h4></div></div></div>
335<div class="toc"><dl>
336<dt><span class="section"><a href="tutorial.html#variant.tutorial.recursive.recursive-wrapper">Recursive types with <code class="computeroutput">recursive_wrapper</code></a></span></dt>
337<dt><span class="section"><a href="tutorial.html#variant.tutorial.recursive.recursive-variant">Recursive types with <code class="computeroutput">make_recursive_variant</code></a></span></dt>
338</dl></div>
339<p>Recursive types facilitate the construction of complex semantics from
340    simple syntax. For instance, nearly every programmer is familiar with the
341    canonical definition of a linked list implementation, whose simple
342    definition allows sequences of unlimited length:
343
344</p>
345<pre class="programlisting">template &lt;typename T&gt;
346struct list_node
347{
348    T data;
349    list_node * next;
350};</pre>
351<p>
352
353  </p>
354<p>The nature of <code class="computeroutput">variant</code> as a generic class template
355    unfortunately precludes the straightforward construction of recursive
356    <code class="computeroutput">variant</code> types. Consider the following attempt to construct
357    a structure for simple mathematical expressions:
358
359    </p>
360<pre class="programlisting">struct add;
361struct sub;
362template &lt;typename OpTag&gt; struct binary_op;
363
364typedef <code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt;
365      int
366    , binary_op&lt;add&gt;
367    , binary_op&lt;sub&gt;
368    &gt; expression;
369
370template &lt;typename OpTag&gt;
371struct binary_op
372{
373    expression left;  // <span class="emphasis"><em>variant instantiated here...</em></span>
374    expression right;
375
376    binary_op( const expression &amp; lhs, const expression &amp; rhs )
377        : left(lhs), right(rhs)
378    {
379    }
380
381}; // <span class="emphasis"><em>...but binary_op not complete until here!</em></span></pre>
382<p>
383
384  </p>
385<p>While well-intentioned, the above approach will not compile because
386    <code class="computeroutput">binary_op</code> is still incomplete when the <code class="computeroutput">variant</code>
387    type <code class="computeroutput">expression</code> is instantiated. Further, the approach suffers
388    from a more significant logical flaw: even if C++ syntax were different
389    such that the above example could be made to "work,"
390    <code class="computeroutput">expression</code> would need to be of infinite size, which is
391    clearly impossible.</p>
392<p>To overcome these difficulties, <code class="computeroutput">variant</code> includes special
393    support for the
394    <code class="computeroutput"><a href="../boost/recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a></code> class
395    template, which breaks the circular dependency at the heart of these
396    problems. Further,
397    <code class="computeroutput"><a href="../boost/make_recursive_variant.html" title="Class template make_recursive_variant">boost::make_recursive_variant</a></code> provides
398    a more convenient syntax for declaring recursive <code class="computeroutput">variant</code>
399    types. Tutorials for use of these facilities is described in
400    <a href="tutorial.html#variant.tutorial.recursive.recursive-wrapper" title="Recursive types with recursive_wrapper">the section called &#8220;Recursive types with <code class="computeroutput">recursive_wrapper</code>&#8221;</a> and
401    <a href="tutorial.html#variant.tutorial.recursive.recursive-variant" title="Recursive types with make_recursive_variant">the section called &#8220;Recursive types with <code class="computeroutput">make_recursive_variant</code>&#8221;</a>.</p>
402<div class="section" lang="en">
403<div class="titlepage"><div><div><h5 class="title">
404<a name="variant.tutorial.recursive.recursive-wrapper"></a>Recursive types with <code class="computeroutput">recursive_wrapper</code></h5></div></div></div>
405<p>The following example demonstrates how <code class="computeroutput">recursive_wrapper</code>
406    could be used to solve the problem presented in
407    <a href="tutorial.html#variant.tutorial.recursive" title="Recursive variant types">the section called &#8220;Recursive <code class="computeroutput">variant</code> types&#8221;</a>:
408
409    </p>
410<pre class="programlisting">typedef <code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt;
411      int
412    , <code class="computeroutput"><a href="../boost/recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a></code>&lt; binary_op&lt;add&gt; &gt;
413    , <code class="computeroutput"><a href="../boost/recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a></code>&lt; binary_op&lt;sub&gt; &gt;
414    &gt; expression;</pre>
415<p>
416
417  </p>
418<p>Because <code class="computeroutput">variant</code> provides special support for
419    <code class="computeroutput">recursive_wrapper</code>, clients may treat the resultant
420    <code class="computeroutput">variant</code> as though the wrapper were not present. This is seen
421    in the implementation of the following visitor, which calculates the value
422    of an <code class="computeroutput">expression</code> without any reference to
423    <code class="computeroutput">recursive_wrapper</code>:
424
425    </p>
426<pre class="programlisting">class calculator : public <code class="computeroutput"><a href="../boost/static_visitor.html" title="Class template static_visitor">boost::static_visitor&lt;int&gt;</a></code>
427{
428public:
429
430    int operator()(int value) const
431    {
432        return value;
433    }
434
435    int operator()(const binary_op&lt;add&gt; &amp; binary) const
436    {
437        return <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>( calculator(), binary.left )
438             + <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>( calculator(), binary.right );
439    }
440
441    int operator()(const binary_op&lt;sub&gt; &amp; binary) const
442    {
443        return <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>( calculator(), binary.left )
444             - <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>( calculator(), binary.right );
445    }
446
447};</pre>
448<p>
449
450  </p>
451<p>Finally, we can demonstrate <code class="computeroutput">expression</code> in action:
452 
453    </p>
454<pre class="programlisting">void f()
455{
456    // result = ((7-3)+8) = 12
457    expression result(
458        binary_op&lt;add&gt;(
459            binary_op&lt;sub&gt;(7,3)
460          , 8
461          )
462      );
463
464    assert( <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>(calculator(),result) == 12 );
465}</pre>
466<p>
467
468  </p>
469</div>
470<div class="section" lang="en">
471<div class="titlepage"><div><div><h5 class="title">
472<a name="variant.tutorial.recursive.recursive-variant"></a>Recursive types with <code class="computeroutput">make_recursive_variant</code></h5></div></div></div>
473<p>For some applications of recursive <code class="computeroutput">variant</code> types, a user
474    may be able to sacrifice the full flexibility of using
475    <code class="computeroutput">recursive_wrapper</code> with <code class="computeroutput">variant</code> for the following
476    convenient syntax:
477
478</p>
479<pre class="programlisting">typedef <code class="computeroutput"><a href="../boost/make_recursive_variant.html" title="Class template make_recursive_variant">boost::make_recursive_variant</a></code>&lt;
480      int
481    , std::vector&lt; boost::recursive_variant_ &gt;
482    &gt;::type int_tree_t;</pre>
483<p>
484
485  </p>
486<p>Use of the resultant <code class="computeroutput">variant</code> type is as expected:
487
488</p>
489<pre class="programlisting">std::vector&lt; int_tree_t &gt; subresult;
490subresult.push_back(3);
491subresult.push_back(5);
492
493std::vector&lt; int_tree_t &gt; result;
494result.push_back(1);
495result.push_back(subresult);
496result.push_back(7);
497
498int_tree_t var(result);</pre>
499<p>
500
501  </p>
502<p>To be clear, one might represent the resultant content of
503    <code class="computeroutput">var</code> as <code class="computeroutput">( 1 ( 3 5 ) 7 )</code>.</p>
504<p>Finally, note that a type sequence can be used to specify the bounded
505    types of a recursive <code class="computeroutput">variant</code> via the use of
506    <code class="computeroutput"><a href="../boost/make_recursive_variant_over.html" title="Class template make_recursive_variant_over">boost::make_recursive_variant_over</a></code>,
507    whose semantics are the same as <code class="computeroutput">make_variant_over</code> (which is
508    described in <a href="tutorial.html#variant.tutorial.over-sequence" title="Using a type sequence to specify bounded types">the section called &#8220;Using a type sequence to specify bounded types&#8221;</a>).</p>
509<p><span class="bold"><strong>Portability</strong></span>: Unfortunately, due to
510    standard conformance issues in several compilers,
511    <code class="computeroutput">make_recursive_variant</code> is not universally supported. On these
512    compilers the library indicates its lack of support via the definition
513    of the preprocessor symbol
514    <code class="computeroutput"><a href="../BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT.html" title="Macro BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT">BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT</a></code>.
515    Thus, unless working with highly-conformant compilers, maximum portability
516    will be achieved by instead using <code class="computeroutput">recursive_wrapper</code>, as
517    described in
518    <a href="tutorial.html#variant.tutorial.recursive.recursive-wrapper" title="Recursive types with recursive_wrapper">the section called &#8220;Recursive types with <code class="computeroutput">recursive_wrapper</code>&#8221;</a>.</p>
519</div>
520</div>
521<div class="section" lang="en">
522<div class="titlepage"><div><div><h4 class="title">
523<a name="variant.tutorial.binary-visitation"></a>Binary visitation</h4></div></div></div>
524<p>As the tutorial above demonstrates, visitation is a powerful mechanism
525    for manipulating <code class="computeroutput">variant</code> content. Binary visitation further
526    extends the power and flexibility of visitation by allowing simultaneous
527    visitation of the content of two different <code class="computeroutput">variant</code>
528    objects.</p>
529<p>Notably this feature requires that binary visitors are incompatible
530    with the visitor objects discussed in the tutorial above, as they must
531    operate on two arguments. The following demonstrates the implementation of
532    a binary visitor:
533
534</p>
535<pre class="programlisting">class are_strict_equals
536    : public <code class="computeroutput"><a href="../boost/static_visitor.html" title="Class template static_visitor">boost::static_visitor</a></code>&lt;bool&gt;
537{
538public:
539
540    template &lt;typename T, typename U&gt;
541    bool operator()( const T &amp;, const U &amp; ) const
542    {
543        return false; // cannot compare different types
544    }
545
546    template &lt;typename T&gt;
547    bool operator()( const T &amp; lhs, const T &amp; rhs ) const
548    {
549        return lhs == rhs;
550    }
551
552};</pre>
553<p>
554
555  </p>
556<p>As expected, the visitor is applied to two <code class="computeroutput">variant</code>
557    arguments by means of <code class="computeroutput">apply_visitor</code>:
558
559</p>
560<pre class="programlisting"><code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt; int, std::string &gt; v1( "hello" );
561
562<code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt; double, std::string &gt; v2( "hello" );
563assert( <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>(are_strict_equals(), v1, v2) );
564
565<code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt; int, const char * &gt; v3( "hello" );
566assert( !<code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>(are_strict_equals(), v1, v3) );</pre>
567<p>
568
569  </p>
570<p>Finally, we must note that the function object returned from the
571    "delayed" form of
572    <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">apply_visitor</a></code> also supports
573    binary visitation, as the following demonstrates:
574
575</p>
576<pre class="programlisting">typedef <code class="computeroutput"><a href="../boost/variant.html" title="Class template variant">boost::variant</a></code>&lt;double, std::string&gt; my_variant;
577
578std::vector&lt; my_variant &gt; seq1;
579seq1.push_back("pi is close to ");
580seq1.push_back(3.14);
581
582std::list&lt; my_variant &gt; seq2;
583seq2.push_back("pi is close to ");
584seq2.push_back(3.14);
585
586are_strict_equals visitor;
587assert( std::equal(
588      v1.begin(), v1.end(), v2.begin()
589    , <code class="computeroutput"><a href="../boost/apply_visitor.html" title="Function apply_visitor">boost::apply_visitor</a></code>( visitor )
590    ) );</pre>
591<p>
592
593  </p>
594</div>
595</div>
596</div>
597<table width="100%"><tr>
598<td align="left"></td>
599<td align="right"><small>Copyright © 2002, 2003 Eric Friedman, Itay Maman</small></td>
600</tr></table>
601<hr>
602<div class="spirit-nav">
603<a accesskey="p" href="../variant.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../variant.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="reference.html"><img src="../images/next.png" alt="Next"></a>
604</div>
605</body>
606</html>
Note: See TracBrowser for help on using the repository browser.