]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/variant/doc/tutorial/advanced.xml
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / variant / doc / tutorial / advanced.xml
CommitLineData
7c673cae
FG
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 Copyright 2013-2014, Antony Polukhin.
7
8 Distributed under the Boost Software License, Version 1.0. (See accompanying
9 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10-->
11<section id="variant.tutorial.advanced">
12 <title>Advanced Topics</title>
13
14<using-namespace name="boost"/>
15<using-class name="boost::variant"/>
16
17<para>This section discusses several features of the library often required
18 for advanced uses of <code>variant</code>. Unlike in the above section, each
19 feature presented below is largely independent of the others. Accordingly,
20 this section is not necessarily intended to be read linearly or in its
21 entirety.</para>
22
23<section id="variant.tutorial.preprocessor">
24 <title>Preprocessor macros</title>
25
26 <para>While the <code>variant</code> class template's variadic parameter
27 list greatly simplifies use for specific instantiations of the template,
28 it significantly complicates use for generic instantiations. For instance,
29 while it is immediately clear how one might write a function accepting a
30 specific <code>variant</code> instantiation, say
31 <code>variant&lt;int, std::string&gt;</code>, it is less clear how one
32 might write a function accepting any given <code>variant</code>.</para>
33
34 <para>Due to the lack of support for true variadic template parameter lists
35 in the C++98 standard, the preprocessor is needed. While the
36 <libraryname>Preprocessor</libraryname> library provides a general and
37 powerful solution, the need to repeat
38 <code><macroname>BOOST_VARIANT_LIMIT_TYPES</macroname></code>
39 unnecessarily clutters otherwise simple code. Therefore, for common
40 use-cases, this library provides its own macro
41 <code><emphasis role="bold"><macroname>BOOST_VARIANT_ENUM_PARAMS</macroname></emphasis></code>.</para>
42
43 <para>This macro simplifies for the user the process of declaring
44 <code>variant</code> types in function templates or explicit partial
45 specializations of class templates, as shown in the following:
46
47<programlisting>// general cases
48template &lt;typename T&gt; void some_func(const T &amp;);
49template &lt;typename T&gt; class some_class;
50
51// function template overload
52template &lt;<macroname>BOOST_VARIANT_ENUM_PARAMS</macroname>(typename T)&gt;
53void some_func(const <classname>boost::variant</classname>&lt;<macroname>BOOST_VARIANT_ENUM_PARAMS</macroname>(T)&gt; &amp;);
54
55// explicit partial specialization
56template &lt;<macroname>BOOST_VARIANT_ENUM_PARAMS</macroname>(typename T)&gt;
57class some_class&lt; <classname>boost::variant</classname>&lt;<macroname>BOOST_VARIANT_ENUM_PARAMS</macroname>(T)&gt; &gt;;</programlisting>
58
59 </para>
60
61</section>
62
63<section id="variant.tutorial.over-sequence">
64 <title>Using a type sequence to specify bounded types</title>
65
66 <para>While convenient for typical uses, the <code>variant</code> class
67 template's variadic template parameter list is limiting in two significant
68 dimensions. First, due to the lack of support for true variadic template
69 parameter lists in C++, the number of parameters must be limited to some
70 implementation-defined maximum (namely,
71 <code><macroname>BOOST_VARIANT_LIMIT_TYPES</macroname></code>).
72 Second, the nature of parameter lists in general makes compile-time
73 manipulation of the lists excessively difficult.</para>
74
75 <para>To solve these problems,
76 <code>make_variant_over&lt; <emphasis>Sequence</emphasis> &gt;</code>
77 exposes a <code>variant</code> whose bounded types are the elements of
78 <code>Sequence</code> (where <code>Sequence</code> is any type fulfilling
79 the requirements of <libraryname>MPL</libraryname>'s
80 <emphasis>Sequence</emphasis> concept). For instance,
81
82<programlisting>typedef <classname>mpl::vector</classname>&lt; std::string &gt; types_initial;
83typedef <classname>mpl::push_front</classname>&lt; types_initial, int &gt;::type types;
84
85<classname>boost::make_variant_over</classname>&lt; types &gt;::type v1;</programlisting>
86
87 behaves equivalently to
88
89<programlisting><classname>boost::variant</classname>&lt; int, std::string &gt; v2;</programlisting>
90
91 </para>
92
93 <para><emphasis role="bold">Portability</emphasis>: Unfortunately, due to
94 standard conformance issues in several compilers,
95 <code>make_variant_over</code> is not universally available. On these
96 compilers the library indicates its lack of support for the syntax via the
97 definition of the preprocessor symbol
98 <code><macroname>BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT</macroname></code>.</para>
99
100</section>
101
102<section id="variant.tutorial.recursive">
103 <title>Recursive <code>variant</code> types</title>
104
105 <para>Recursive types facilitate the construction of complex semantics from
106 simple syntax. For instance, nearly every programmer is familiar with the
107 canonical definition of a linked list implementation, whose simple
108 definition allows sequences of unlimited length:
109
110<programlisting>template &lt;typename T&gt;
111struct list_node
112{
113 T data;
114 list_node * next;
115};</programlisting>
116
117 </para>
118
119 <para>The nature of <code>variant</code> as a generic class template
120 unfortunately precludes the straightforward construction of recursive
121 <code>variant</code> types. Consider the following attempt to construct
122 a structure for simple mathematical expressions:
123
124 <programlisting>struct add;
125struct sub;
126template &lt;typename OpTag&gt; struct binary_op;
127
128typedef <classname>boost::variant</classname>&lt;
129 int
130 , binary_op&lt;add&gt;
131 , binary_op&lt;sub&gt;
132 > expression;
133
134template &lt;typename OpTag&gt;
135struct binary_op
136{
137 expression left; // <emphasis>variant instantiated here...</emphasis>
138 expression right;
139
140 binary_op( const expression &amp; lhs, const expression &amp; rhs )
141 : left(lhs), right(rhs)
142 {
143 }
144
145}; // <emphasis>...but binary_op not complete until here!</emphasis></programlisting>
146
147 </para>
148
149 <para>While well-intentioned, the above approach will not compile because
150 <code>binary_op</code> is still incomplete when the <code>variant</code>
151 type <code>expression</code> is instantiated. Further, the approach suffers
152 from a more significant logical flaw: even if C++ syntax were different
153 such that the above example could be made to &quot;work,&quot;
154 <code>expression</code> would need to be of infinite size, which is
155 clearly impossible.</para>
156
157 <para>To overcome these difficulties, <code>variant</code> includes special
158 support for the
159 <code><classname>boost::recursive_wrapper</classname></code> class
160 template, which breaks the circular dependency at the heart of these
161 problems. Further,
162 <code><classname>boost::make_recursive_variant</classname></code> provides
163 a more convenient syntax for declaring recursive <code>variant</code>
164 types. Tutorials for use of these facilities is described in
165 <xref linkend="variant.tutorial.recursive.recursive-wrapper"/> and
166 <xref linkend="variant.tutorial.recursive.recursive-variant"/>.</para>
167
168<section id="variant.tutorial.recursive.recursive-wrapper">
169 <title>Recursive types with <code>recursive_wrapper</code></title>
170
171 <para>The following example demonstrates how <code>recursive_wrapper</code>
172 could be used to solve the problem presented in
173 <xref linkend="variant.tutorial.recursive"/>:
174
175 <programlisting>typedef <classname>boost::variant</classname>&lt;
176 int
177 , <classname>boost::recursive_wrapper</classname>&lt; binary_op&lt;add&gt; &gt;
178 , <classname>boost::recursive_wrapper</classname>&lt; binary_op&lt;sub&gt; &gt;
179 &gt; expression;</programlisting>
180
181 </para>
182
183 <para>Because <code>variant</code> provides special support for
184 <code>recursive_wrapper</code>, clients may treat the resultant
185 <code>variant</code> as though the wrapper were not present. This is seen
186 in the implementation of the following visitor, which calculates the value
187 of an <code>expression</code> without any reference to
188 <code>recursive_wrapper</code>:
189
190 <programlisting>class calculator : public <classname>boost::static_visitor&lt;int&gt;</classname>
191{
192public:
193
194 int operator()(int value) const
195 {
196 return value;
197 }
198
199 int operator()(const binary_op&lt;add&gt; &amp; binary) const
200 {
201 return <functionname>boost::apply_visitor</functionname>( calculator(), binary.left )
202 + <functionname>boost::apply_visitor</functionname>( calculator(), binary.right );
203 }
204
205 int operator()(const binary_op&lt;sub&gt; &amp; binary) const
206 {
207 return <functionname>boost::apply_visitor</functionname>( calculator(), binary.left )
208 - <functionname>boost::apply_visitor</functionname>( calculator(), binary.right );
209 }
210
211};</programlisting>
212
213 </para>
214
215 <para>Finally, we can demonstrate <code>expression</code> in action:
216
217 <programlisting>void f()
218{
219 // result = ((7-3)+8) = 12
220 expression result(
221 binary_op&lt;add&gt;(
222 binary_op&lt;sub&gt;(7,3)
223 , 8
224 )
225 );
226
227 assert( <functionname>boost::apply_visitor</functionname>(calculator(),result) == 12 );
228}</programlisting>
229
230 </para>
231
232 <para><emphasis role="bold">Performance</emphasis>: <classname>boost::recursive_wrapper</classname>
233 has no empty state, which makes its move constructor not very optimal. Consider using <code>std::unique_ptr</code>
234 or some other safe pointer for better performance on C++11 compatible compilers.</para>
235
236</section>
237
238<section id="variant.tutorial.recursive.recursive-variant">
239 <title>Recursive types with <code>make_recursive_variant</code></title>
240
241 <para>For some applications of recursive <code>variant</code> types, a user
242 may be able to sacrifice the full flexibility of using
243 <code>recursive_wrapper</code> with <code>variant</code> for the following
244 convenient syntax:
245
246<programlisting>typedef <classname>boost::make_recursive_variant</classname>&lt;
247 int
248 , std::vector&lt; boost::recursive_variant_ &gt;
249 &gt;::type int_tree_t;</programlisting>
250
251 </para>
252
253 <para>Use of the resultant <code>variant</code> type is as expected:
254
255<programlisting>std::vector&lt; int_tree_t &gt; subresult;
256subresult.push_back(3);
257subresult.push_back(5);
258
259std::vector&lt; int_tree_t &gt; result;
260result.push_back(1);
261result.push_back(subresult);
262result.push_back(7);
263
264int_tree_t var(result);</programlisting>
265
266 </para>
267
268 <para>To be clear, one might represent the resultant content of
269 <code>var</code> as <code>( 1 ( 3 5 ) 7 )</code>.</para>
270
271 <para>Finally, note that a type sequence can be used to specify the bounded
272 types of a recursive <code>variant</code> via the use of
273 <code><classname>boost::make_recursive_variant_over</classname></code>,
274 whose semantics are the same as <code>make_variant_over</code> (which is
275 described in <xref linkend="variant.tutorial.over-sequence"/>).</para>
276
277 <para><emphasis role="bold">Portability</emphasis>: Unfortunately, due to
278 standard conformance issues in several compilers,
279 <code>make_recursive_variant</code> is not universally supported. On these
280 compilers the library indicates its lack of support via the definition
281 of the preprocessor symbol
282 <code><macroname>BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT</macroname></code>.
283 Thus, unless working with highly-conformant compilers, maximum portability
284 will be achieved by instead using <code>recursive_wrapper</code>, as
285 described in
286 <xref linkend="variant.tutorial.recursive.recursive-wrapper"/>.</para>
287
288</section>
289
290</section> <!--/tutorial.recursive-->
291
292<section id="variant.tutorial.binary-visitation">
293 <title>Binary visitation</title>
294
295 <para>As the tutorial above demonstrates, visitation is a powerful mechanism
296 for manipulating <code>variant</code> content. Binary visitation further
297 extends the power and flexibility of visitation by allowing simultaneous
298 visitation of the content of two different <code>variant</code>
299 objects.</para>
300
301 <para>Notably this feature requires that binary visitors are incompatible
302 with the visitor objects discussed in the tutorial above, as they must
303 operate on two arguments. The following demonstrates the implementation of
304 a binary visitor:
305
306<programlisting>class are_strict_equals
307 : public <classname>boost::static_visitor</classname>&lt;bool&gt;
308{
309public:
310
311 template &lt;typename T, typename U&gt;
312 bool operator()( const T &amp;, const U &amp; ) const
313 {
314 return false; // cannot compare different types
315 }
316
317 template &lt;typename T&gt;
318 bool operator()( const T &amp; lhs, const T &amp; rhs ) const
319 {
320 return lhs == rhs;
321 }
322
323};</programlisting>
324
325 </para>
326
327 <para>As expected, the visitor is applied to two <code>variant</code>
328 arguments by means of <code>apply_visitor</code>:
329
330<programlisting><classname>boost::variant</classname>&lt; int, std::string &gt; v1( "hello" );
331
332<classname>boost::variant</classname>&lt; double, std::string &gt; v2( "hello" );
333assert( <functionname>boost::apply_visitor</functionname>(are_strict_equals(), v1, v2) );
334
335<classname>boost::variant</classname>&lt; int, const char * &gt; v3( "hello" );
336assert( !<functionname>boost::apply_visitor</functionname>(are_strict_equals(), v1, v3) );</programlisting>
337
338 </para>
339
340 <para>Finally, we must note that the function object returned from the
341 &quot;delayed&quot; form of
342 <code><functionname>apply_visitor</functionname></code> also supports
343 binary visitation, as the following demonstrates:
344
345<programlisting>typedef <classname>boost::variant</classname>&lt;double, std::string&gt; my_variant;
346
347std::vector&lt; my_variant &gt; seq1;
348seq1.push_back("pi is close to ");
349seq1.push_back(3.14);
350
351std::list&lt; my_variant &gt; seq2;
352seq2.push_back("pi is close to ");
353seq2.push_back(3.14);
354
355are_strict_equals visitor;
356assert( std::equal(
357 seq1.begin(), seq1.end(), seq2.begin()
358 , <functionname>boost::apply_visitor</functionname>( visitor )
359 ) );</programlisting>
360
361 </para>
362
363</section>
364
365<section id="variant.tutorial.multi-visitation">
366 <title>Multi visitation</title>
367
368 <para>Multi visitation extends the power and flexibility of visitation by allowing simultaneous
369 visitation of the content of three and more different <code>variant</code>
370 objects. Note that header for multi visitors shall be included separately.</para>
371
372 <para>Notably this feature requires that multi visitors are incompatible
373 with the visitor objects discussed in the tutorial above, as they must
374 operate on same amout of arguments that was passed to <code>apply_visitor</code>.
375 The following demonstrates the implementation of a multi visitor for three parameters:
376
377<programlisting>
378#include &lt;boost/variant/multivisitors.hpp&gt;
379
380typedef <classname>boost::variant</classname>&lt;int, double, bool&gt; bool_like_t;
381typedef <classname>boost::variant</classname>&lt;int, double&gt; arithmetics_t;
382
383struct if_visitor: public <classname>boost::static_visitor</classname>&lt;arithmetics_t&gt; {
384 template &lt;class T1, class T2&gt;
385 arithmetics_t operator()(bool b, T1 v1, T2 v2) const {
386 if (b) {
387 return v1;
388 } else {
389 return v2;
390 }
391 }
392};
393</programlisting>
394 </para>
395
396 <para>As expected, the visitor is applied to three <code>variant</code>
397 arguments by means of <code>apply_visitor</code>:
398
399<programlisting>
400bool_like_t v0(true), v1(1), v2(2.0);
401
402assert(
403 <functionname>boost::apply_visitor</functionname>(if_visitor(), v0, v1, v2)
404 ==
405 arithmetics_t(1)
406);
407</programlisting>
408 </para>
409
410 <para>Finally, we must note that multi visitation does not support
411 &quot;delayed&quot; form of
412 <code><functionname>apply_visitor</functionname> if
413 <macroname>BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES</macroname> is defined</code>.
414 </para>
415
416</section>
417
418
419</section>