]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/variant/doc/tutorial/basic.xml
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / variant / doc / tutorial / basic.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
3 "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
4 <!--
5 Copyright 2003, Eric Friedman, Itay Maman.
6
7 Distributed under the Boost Software License, Version 1.0. (See accompanying
8 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 -->
10 <section id="variant.tutorial.basic">
11 <title>Basic Usage</title>
12
13 <using-namespace name="boost"/>
14 <using-class name="boost::variant"/>
15
16 <para>A discriminated union container on some set of types is defined by
17 instantiating the <code><classname>boost::variant</classname></code> class
18 template with the desired types. These types are called
19 <emphasis role="bold">bounded types</emphasis> and are subject to the
20 requirements of the
21 <link linkend="variant.concepts.bounded-type"><emphasis>BoundedType</emphasis></link>
22 concept. Any number of bounded types may be specified, up to some
23 implementation-defined limit (see
24 <code><macroname>BOOST_VARIANT_LIMIT_TYPES</macroname></code>).</para>
25
26 <para>For example, the following declares a discriminated union container on
27 <code>int</code> and <code>std::string</code>:
28
29 <programlisting><classname>boost::variant</classname>&lt; int, std::string &gt; v;</programlisting>
30
31 </para>
32
33 <para>By default, a <code>variant</code> default-constructs its first
34 bounded type, so <code>v</code> initially contains <code>int(0)</code>. If
35 this is not desired, or if the first bounded type is not
36 default-constructible, a <code>variant</code> can be constructed
37 directly from any value convertible to one of its bounded types. Similarly,
38 a <code>variant</code> can be assigned any value convertible to one of its
39 bounded types, as demonstrated in the following:
40
41 <programlisting>v = "hello";</programlisting>
42
43 </para>
44
45 <para>Now <code>v</code> contains a <code>std::string</code> equal to
46 <code>"hello"</code>. We can demonstrate this by
47 <emphasis role="bold">streaming</emphasis>&nbsp;<code>v</code> to standard
48 output:
49
50 <programlisting>std::cout &lt;&lt; v &lt;&lt; std::endl;</programlisting>
51
52 </para>
53
54 <para>Usually though, we would like to do more with the content of a
55 <code>variant</code> than streaming. Thus, we need some way to access the
56 contained value. There are two ways to accomplish this:
57 <code><functionname>apply_visitor</functionname></code>, which is safest
58 and very powerful, and
59 <code><functionname>get</functionname>&lt;T&gt;</code>, which is
60 sometimes more convenient to use.</para>
61
62 <para>For instance, suppose we wanted to concatenate to the string contained
63 in <code>v</code>. With <emphasis role="bold">value retrieval</emphasis>
64 by <code><functionname>get</functionname></code>, this may be accomplished
65 quite simply, as seen in the following:
66
67 <programlisting>std::string&amp; str = <functionname>boost::get</functionname>&lt;std::string&gt;(v);
68 str += " world! ";</programlisting>
69
70 </para>
71
72 <para>As desired, the <code>std::string</code> contained by <code>v</code> now
73 is equal to <code>"hello world! "</code>. Again, we can demonstrate this by
74 streaming <code>v</code> to standard output:
75
76 <programlisting>std::cout &lt;&lt; v &lt;&lt; std::endl;</programlisting>
77
78 </para>
79
80 <para>While use of <code>get</code> is perfectly acceptable in this trivial
81 example, <code>get</code> generally suffers from several significant
82 shortcomings. For instance, if we were to write a function accepting a
83 <code>variant&lt;int, std::string&gt;</code>, we would not know whether
84 the passed <code>variant</code> contained an <code>int</code> or a
85 <code>std::string</code>. If we insisted upon continued use of
86 <code>get</code>, we would need to query the <code>variant</code> for its
87 contained type. The following function, which &quot;doubles&quot; the
88 content of the given <code>variant</code>, demonstrates this approach:
89
90 <programlisting>void times_two( boost::variant&lt; int, std::string &gt; &amp; operand )
91 {
92 if ( int* pi = <functionname>boost::get</functionname>&lt;int&gt;( &amp;operand ) )
93 *pi *= 2;
94 else if ( std::string* pstr = <functionname>boost::get</functionname>&lt;std::string&gt;( &amp;operand ) )
95 *pstr += *pstr;
96 }</programlisting>
97
98 </para>
99
100 <para>However, such code is quite brittle, and without careful attention will
101 likely lead to the introduction of subtle logical errors detectable only at
102 runtime. For instance, consider if we wished to extend
103 <code>times_two</code> to operate on a <code>variant</code> with additional
104 bounded types. Specifically, let's add
105 <code>std::complex&lt;double&gt;</code> to the set. Clearly, we would need
106 to at least change the function declaration:
107
108 <programlisting>void times_two( boost::variant&lt; int, std::string, std::complex&lt;double&gt; &gt; &amp; operand )
109 {
110 // as above...?
111 }</programlisting>
112
113 </para>
114
115 <para>Of course, additional changes are required, for currently if the passed
116 <code>variant</code> in fact contained a <code>std::complex</code> value,
117 <code>times_two</code> would silently return -- without any of the desired
118 side-effects and without any error. In this case, the fix is obvious. But in
119 more complicated programs, it could take considerable time to identify and
120 locate the error in the first place.</para>
121
122 <para>Thus, real-world use of <code>variant</code> typically demands an access
123 mechanism more robust than <code>get</code>. For this reason,
124 <code>variant</code> supports compile-time checked
125 <emphasis role="bold">visitation</emphasis> via
126 <code><functionname>apply_visitor</functionname></code>. Visitation requires
127 that the programmer explicitly handle (or ignore) each bounded type. Failure
128 to do so results in a compile-time error.</para>
129
130 <para>Visitation of a <code>variant</code> requires a visitor object. The
131 following demonstrates one such implementation of a visitor implementating
132 behavior identical to <code>times_two</code>:
133
134 <programlisting>class times_two_visitor
135 : public <classname>boost::static_visitor</classname>&lt;&gt;
136 {
137 public:
138
139 void operator()(int &amp; i) const
140 {
141 i *= 2;
142 }
143
144 void operator()(std::string &amp; str) const
145 {
146 str += str;
147 }
148
149 };</programlisting>
150
151 </para>
152
153 <para>With the implementation of the above visitor, we can then apply it to
154 <code>v</code>, as seen in the following:
155
156 <programlisting><functionname>boost::apply_visitor</functionname>( times_two_visitor(), v );</programlisting>
157
158 </para>
159
160 <para>As expected, the content of <code>v</code> is now a
161 <code>std::string</code> equal to <code>"hello world! hello world! "</code>.
162 (We'll skip the verification this time.)</para>
163
164 <para>In addition to enhanced robustness, visitation provides another
165 important advantage over <code>get</code>: the ability to write generic
166 visitors. For instance, the following visitor will &quot;double&quot; the
167 content of <emphasis>any</emphasis>&nbsp;<code>variant</code> (provided its
168 bounded types each support operator+=):
169
170 <programlisting>class times_two_generic
171 : public <classname>boost::static_visitor</classname>&lt;&gt;
172 {
173 public:
174
175 template &lt;typename T&gt;
176 void operator()( T &amp; operand ) const
177 {
178 operand += operand;
179 }
180
181 };</programlisting>
182
183 </para>
184
185 <para>Again, <code>apply_visitor</code> sets the wheels in motion:
186
187 <programlisting><functionname>boost::apply_visitor</functionname>( times_two_generic(), v );</programlisting>
188
189 </para>
190
191 <para>While the initial setup costs of visitation may exceed that required for
192 <code>get</code>, the benefits quickly become significant. Before concluding
193 this section, we should explore one last benefit of visitation with
194 <code>apply_visitor</code>:
195 <emphasis role="bold">delayed visitation</emphasis>. Namely, a special form
196 of <code>apply_visitor</code> is available that does not immediately apply
197 the given visitor to any <code>variant</code> but rather returns a function
198 object that operates on any <code>variant</code> given to it. This behavior
199 is particularly useful when operating on sequences of <code>variant</code>
200 type, as the following demonstrates:
201
202 <programlisting>std::vector&lt; <classname>boost::variant</classname>&lt;int, std::string&gt; &gt; vec;
203 vec.push_back( 21 );
204 vec.push_back( "hello " );
205
206 times_two_generic visitor;
207 std::for_each(
208 vec.begin(), vec.end()
209 , <functionname>boost::apply_visitor</functionname>(visitor)
210 );</programlisting>
211
212 </para>
213
214 </section>