variant.tutorial.html 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Tutorial</title><link rel="stylesheet" href="reference.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.61.3"><link rel="home" href="index.html" title="The Boost C++ Libraries"><link rel="up" href="variant.html" title="Boost.Variant"><link rel="previous" href="variant.html" title="Boost.Variant"><link rel="next" href="variant.reference.html" title="Reference"><link rel="chapter" href="libraries.html" title="The Boost C++ Libraries"><link rel="chapter" href="any.html" title="Boost.Any"><link rel="refentry" href="class.boost.bad_any_cast.html" title="Class bad_any_cast"><link rel="refentry" href="class.boost.any.html" title="Class any"><link rel="refentry" href="id2383300-bb.html" title="Function any_cast"><link rel="chapter" href="array.html" title="Boost.Array"><link rel="refentry" href="class.boost.array.html" title="Class template array"><link rel="chapter" href="function.html" title="Boost.Function"><link rel="refentry" href="class.boost.bad_function_call.html" title="Class bad_function_call"><link rel="refentry" href="class.boost.function_base.html" title="Class function_base"><link rel="refentry" href="class.boost.functionN.html" title="Class template functionN"><link rel="refentry" href="class.boost.function.html" title="Class template function"><link rel="chapter" href="ref.html" title="Boost.Ref"><link rel="refentry" href="class.boost.reference_wrapper.html" title="Class template reference_wrapper"><link rel="refentry" href="class.boost.is_reference_wrapper.html" title="Class template is_reference_wrapper"><link rel="refentry" href="class.boost.unwrap_reference.html" title="Class template unwrap_reference"><link rel="chapter" href="signals.html" title="Boost.Signals"><link rel="refentry" href="class.boost.signalN.html" title="Class template signalN"><link rel="refentry" href="class.boost.signal.html" title="Class template signal"><link rel="refentry" href="class.boost.slot.html" title="Class template slot"><link rel="refentry" href="class.boost.signals.trackable.html" title="Class trackable"><link rel="refentry" href="class.boost.signals.connection.html" title="Class connection"><link rel="refentry" href="class.boost.signals.scoped_connection.html" title="Class scoped_connection"><link rel="refentry" href="id2532119-bb.html" title="Function template visit_each"><link rel="refentry" href="class.boost.last_value.html" title="Class template last_value"><link rel="refentry" href="id2354683-bb.html" title="Class last_value&lt;void&gt;"><link rel="chapter" href="variant.html" title="Boost.Variant"><link rel="refentry" href="BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES"><link rel="refentry" href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS"><link rel="refentry" href="BOOST_VARIANT_ENUM_SHIFTED_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_SHIFTED_PARAMS"><link rel="refentry" href="BOOST_VARIANT_NO_REFERENCE_SUPPORT.html" title="Macro BOOST_VARIANT_NO_REFERENCE_SUPPORT"><link rel="refentry" href="BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT.html" title="Macro BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT"><link rel="refentry" href="BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT.html" title="Macro BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT"><link rel="refentry" href="class.boost.variant.html" title="Class template variant"><link rel="refentry" href="id2518553-bb.html" title="Function template swap"><link rel="refentry" href="id2524211-bb.html" title="Function template operator&lt;&lt;"><link rel="refentry" href="class.boost.make_variant_over.html" title="Class template make_variant_over"><link rel="refentry" href="class.boost.make_recursive_variant.html" title="Class template make_recursive_variant"><link rel="refentry" href="class.boost.make_recursive_variant_over.html" title="Class template make_recursive_variant_over"><link rel="refentry" href="class.boost.recursive_wrapper.html" title="Class template recursive_wrapper"><link rel="refentry" href="class.boost.is_recursive_wrapper.html" title="Class template is_recursive_wrapper"><link rel="refentry" href="class.boost.unwrap_recursive_wrapper.html" title="Class template unwrap_recursive_wrapper"><link rel="refentry" href="class.boost.apply_visitor_delayed_t.html" title="Class template apply_visitor_delayed_t"><link rel="refentry" href="id2557051-bb.html" title="Function apply_visitor"><link rel="refentry" href="class.boost.bad_get.html" title="Class bad_get"><link rel="refentry" href="id2493238-bb.html" title="Function get"><link rel="refentry" href="class.boost.bad_visit.html" title="Class bad_visit"><link rel="refentry" href="class.boost.static_visitor.html" title="Class template static_visitor"><link rel="refentry" href="class.boost.visitor_ptr_t.html" title="Class template visitor_ptr_t"><link rel="refentry" href="id2544445-bb.html" title="Function template visitor_ptr"><link rel="chapter" href="boostbook.html" title="The BoostBook Documentation Format"><link rel="refentry" href="boostbook.dtd.class-specialization.html" title="
  2. BoostBook element class-specialization"><link rel="refentry" href="boostbook.dtd.link-test.html" title="
  3. BoostBook element link-test"><link rel="refentry" href="boostbook.dtd.link-fail-test.html" title="
  4. BoostBook element link-fail-test"><link rel="refentry" href="boostbook.dtd.typedef.html" title="
  5. BoostBook element typedef"><link rel="refentry" href="boostbook.dtd.static-constant.html" title="
  6. BoostBook element static-constant"><link rel="refentry" href="boostbook.dtd.code.html" title="
  7. BoostBook element code"><link rel="refentry" href="boostbook.dtd.destructor.html" title="
  8. BoostBook element destructor"><link rel="refentry" href="boostbook.dtd.template-type-parameter.html" title="
  9. BoostBook element template-type-parameter"><link rel="refentry" href="boostbook.dtd.description.html" title="
  10. BoostBook element description"><link rel="refentry" href="boostbook.dtd.librarylist.html" title="
  11. BoostBook element librarylist"><link rel="refentry" href="boostbook.dtd.library-reference.html" title="
  12. BoostBook element library-reference"><link rel="refentry" href="boostbook.dtd.boostbook.html" title="
  13. BoostBook element boostbook"><link rel="refentry" href="boostbook.dtd.union.html" title="
  14. BoostBook element union"><link rel="refentry" href="boostbook.dtd.inherit.html" title="
  15. BoostBook element inherit"><link rel="refentry" href="boostbook.dtd.template-varargs.html" title="
  16. BoostBook element template-varargs"><link rel="refentry" href="boostbook.dtd.source.html" title="
  17. BoostBook element source"><link rel="refentry" href="boostbook.dtd.function.html" title="
  18. BoostBook element function"><link rel="refentry" href="boostbook.dtd.postconditions.html" title="
  19. BoostBook element postconditions"><link rel="refentry" href="boostbook.dtd.compile-test.html" title="
  20. BoostBook element compile-test"><link rel="refentry" href="boostbook.dtd.method.html" title="
  21. BoostBook element method"><link rel="refentry" href="boostbook.dtd.snippet.html" title="
  22. BoostBook element snippet"><link rel="refentry" href="boostbook.dtd.constructor.html" title="
  23. BoostBook element constructor"><link rel="refentry" href="boostbook.dtd.namespace.html" title="
  24. BoostBook element namespace"><link rel="refentry" href="boostbook.dtd.if-fails.html" title="
  25. BoostBook element if-fails"><link rel="refentry" href="boostbook.dtd.free-function-group.html" title="
  26. BoostBook element free-function-group"><link rel="refentry" href="boostbook.dtd.functionname.html" title="
  27. BoostBook element functionname"><link rel="refentry" href="boostbook.dtd.librarycategory.html" title="
  28. BoostBook element librarycategory"><link rel="refentry" href="boostbook.dtd.notes.html" title="
  29. BoostBook element notes"><link rel="refentry" href="boostbook.dtd.data-member.html" title="
  30. BoostBook element data-member"><link rel="refentry" href="boostbook.dtd.specialization.html" title="
  31. BoostBook element specialization"><link rel="refentry" href="boostbook.dtd.union-specialization.html" title="
  32. BoostBook element union-specialization"><link rel="refentry" href="boostbook.dtd.throws.html" title="
  33. BoostBook element throws"><link rel="refentry" href="boostbook.dtd.template-arg.html" title="
  34. BoostBook element template-arg"><link rel="refentry" href="boostbook.dtd.method-group.html" title="
  35. BoostBook element method-group"><link rel="refentry" href="boostbook.dtd.requirement.html" title="
  36. BoostBook element requirement"><link rel="refentry" href="boostbook.dtd.precondition.html" title="
  37. BoostBook element precondition"><link rel="refentry" href="boostbook.dtd.paramtype.html" title="
  38. BoostBook element paramtype"><link rel="refentry" href="boostbook.dtd.using-class.html" title="
  39. BoostBook element using-class"><link rel="refentry" href="boostbook.dtd.run-test.html" title="
  40. BoostBook element run-test"><link rel="refentry" href="boostbook.dtd.librarypurpose.html" title="
  41. BoostBook element librarypurpose"><link rel="refentry" href="boostbook.dtd.copy-assignment.html" title="
  42. BoostBook element copy-assignment"><link rel="refentry" href="boostbook.dtd.run-fail-test.html" title="
  43. BoostBook element run-fail-test"><link rel="refentry" href="boostbook.dtd.template.html" title="
  44. BoostBook element template"><link rel="refentry" href="boostbook.dtd.compile-fail-test.html" title="
  45. BoostBook element compile-fail-test"><link rel="refentry" href="boostbook.dtd.returns.html" title="
  46. BoostBook element returns"><link rel="refentry" href="boostbook.dtd.default.html" title="
  47. BoostBook element default"><link rel="refentry" href="boostbook.dtd.parameter.html" title="
  48. BoostBook element parameter"><link rel="refentry" href="boostbook.dtd.signature.html" title="
  49. BoostBook element signature"><link rel="refentry" href="boostbook.dtd.overloaded-function.html" title="
  50. BoostBook element overloaded-function"><link rel="refentry" href="boostbook.dtd.class.html" title="
  51. BoostBook element class"><link rel="refentry" href="boostbook.dtd.librarycategorydef.html" title="
  52. BoostBook element librarycategorydef"><link rel="refentry" href="boostbook.dtd.type.html" title="
  53. BoostBook element type"><link rel="refentry" href="boostbook.dtd.enumvalue.html" title="
  54. BoostBook element enumvalue"><link rel="refentry" href="boostbook.dtd.overloaded-method.html" title="
  55. BoostBook element overloaded-method"><link rel="refentry" href="boostbook.dtd.programlisting.html" title="
  56. BoostBook element programlisting"><link rel="refentry" href="boostbook.dtd.complexity.html" title="
  57. BoostBook element complexity"><link rel="refentry" href="boostbook.dtd.purpose.html" title="
  58. BoostBook element purpose"><link rel="refentry" href="boostbook.dtd.template-nontype-parameter.html" title="
  59. BoostBook element template-nontype-parameter"><link rel="refentry" href="boostbook.dtd.library.html" title="
  60. BoostBook element library"><link rel="refentry" href="boostbook.dtd.librarycategorylist.html" title="
  61. BoostBook element librarycategorylist"><link rel="refentry" href="boostbook.dtd.using-namespace.html" title="
  62. BoostBook element using-namespace"><link rel="refentry" href="boostbook.dtd.struct-specialization.html" title="
  63. BoostBook element struct-specialization"><link rel="refentry" href="boostbook.dtd.struct.html" title="
  64. BoostBook element struct"><link rel="refentry" href="boostbook.dtd.lib.html" title="
  65. BoostBook element lib"><link rel="refentry" href="boostbook.dtd.enum.html" title="
  66. BoostBook element enum"><link rel="refentry" href="boostbook.dtd.requires.html" title="
  67. BoostBook element requires"><link rel="refentry" href="boostbook.dtd.effects.html" title="
  68. BoostBook element effects"><link rel="refentry" href="boostbook.dtd.libraryname.html" title="
  69. BoostBook element libraryname"><link rel="refentry" href="boostbook.dtd.libraryinfo.html" title="
  70. BoostBook element libraryinfo"><link rel="refentry" href="boostbook.dtd.testsuite.html" title="
  71. BoostBook element testsuite"><link rel="refentry" href="boostbook.dtd.header.html" title="
  72. BoostBook element header"><link rel="refentry" href="boostbook.dtd.rationale.html" title="
  73. BoostBook element rationale"><link rel="refentry" href="Assignable.html" title="Concept Assignable"><link rel="refentry" href="InputIterator.html" title="Concept InputIterator"><link rel="refentry" href="OutputIterator.html" title="Concept OutputIterator"><link rel="refentry" href="ForwardIterator.html" title="Concept ForwardIterator"><link rel="refentry" href="BidirectionalIterator.html" title="Concept BidirectionalIterator"><link rel="refentry" href="RandomAccessIterator.html" title="Concept RandomAccessIterator"><link rel="refentry" href="DefaultConstructible.html" title="Concept DefaultConstructible"><link rel="refentry" href="CopyConstructible.html" title="Concept CopyConstructible"><link rel="refentry" href="EqualityComparable.html" title="Concept EqualityComparable"><link rel="refentry" href="LessThanComparable.html" title="Concept LessThanComparable"><link rel="refentry" href="SignedInteger.html" title="Concept SignedInteger"><link rel="subsection" href="variant.tutorial.html#variant.tutorial.basic" title="Basic Usage"><link rel="subsection" href="variant.tutorial.html#variant.tutorial.advanced" title="Advanced Topics"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" border="1" cellpadding="2" bgcolor="#007F7F"><tr><td bgcolor="#FFFFFF"><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277" height="86"></td><td><a href="../../index.htm"><font color="#FFFFFF" size="4" face="Arial">Home</font></a></td><td><a href="libraries.html"><font color="#FFFFFF" size="4" face="Arial">Libraries</font></a></td><td><a href="../../people/people.htm"><font color="#FFFFFF" size="4" face="Arial">People</font></a></td><td><a href="../../more/faq.htm"><font color="#FFFFFF" size="4" face="Arial">FAQ</font></a></td><td><a href="../../more/index.htm"><font color="#FFFFFF" size="4" face="Arial">More</font></a></td></tr></table><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="variant.tutorial"></a>Tutorial</h3></div></div><div></div></div><div class="toc"><dl><dt><a href="variant.tutorial.html#variant.tutorial.basic">Basic Usage</a></dt><dt><a href="variant.tutorial.html#variant.tutorial.advanced">Advanced Topics</a></dt></dl></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="variant.tutorial.basic"></a>Basic Usage</h4></div></div><div></div></div><p>A discriminated union container on some set of types is defined by
  74. instantiating the <tt class="computeroutput"><a href="class.boost.variant.html" title="Class template variant">boost::variant</a></tt> class
  75. template with the desired types. These types are called
  76. <span class="bold"><b>bounded types</b></span> and are subject to the
  77. requirements of the
  78. <a href="variant.reference.html#variant.concepts.bounded-type" title="BoundedType"><span class="emphasis"><em>BoundedType</em></span></a>
  79. concept. Any number of bounded types may be specified, up to some
  80. implementation-defined limit (see
  81. <tt class="computeroutput"><a href="BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES">BOOST_VARIANT_LIMIT_TYPES</a></tt>).</p><p>For example, the following declares a discriminated union container on
  82. <tt class="computeroutput">int</tt> and <tt class="computeroutput">std::string</tt>:
  83. </p><pre class="programlisting"><a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt; int, std::string &gt; v;</pre><p>By default, a <tt class="computeroutput">variant</tt> default-constructs its first
  84. bounded type, so <tt class="computeroutput">v</tt> initially contains <tt class="computeroutput">int(0)</tt>. If
  85. this is not desired, or if the first bounded type is not
  86. default-constructible, a <tt class="computeroutput">variant</tt> can be constructed
  87. directly from any value convertible to one of its bounded types. Similarly,
  88. a <tt class="computeroutput">variant</tt> can be assigned any value convertible to one of its
  89. bounded types, as demonstrated in the following:
  90. </p><pre class="programlisting">v = "hello";</pre><p>Now <tt class="computeroutput">v</tt> contains a <tt class="computeroutput">std::string</tt> equal to
  91. <tt class="computeroutput">"hello"</tt>. We can demonstrate this by
  92. <span class="bold"><b>streaming</b></span><tt class="computeroutput">v</tt> to standard
  93. output:
  94. </p><pre class="programlisting">std::cout &lt;&lt; v &lt;&lt; std::endl;</pre><p>Usually though, we would like to do more with the content of a
  95. <tt class="computeroutput">variant</tt> than streaming. Thus, we need some way to access the
  96. contained value. There are two ways to accomplish this:
  97. <tt class="computeroutput"><a href="id2557051-bb.html" title="Function apply_visitor">apply_visitor</a></tt>, which is safest
  98. and very powerful, and
  99. <tt class="computeroutput"><a href="id2493238-bb.html" title="Function get">get</a>&lt;T&gt;</tt>, which is
  100. sometimes more convenient to use.</p><p>For instance, suppose we wanted to concatenate to the string contained
  101. in <tt class="computeroutput">v</tt>. With <span class="bold"><b>value retrieval</b></span>
  102. by <tt class="computeroutput"><a href="id2493238-bb.html" title="Function get">get</a></tt>, this may be accomplished
  103. quite simply, as seen in the following:
  104. </p><pre class="programlisting">std::string&amp; str = <a href="id2493238-bb.html" title="Function get">boost::get</a>&lt;std::string&gt;(v);
  105. str += " world! ";</pre><p>As desired, the <tt class="computeroutput">std::string</tt> contained by <tt class="computeroutput">v</tt> now
  106. is equal to <tt class="computeroutput">"hello world! "</tt>. Again, we can demonstrate this by
  107. streaming <tt class="computeroutput">v</tt> to standard output:
  108. </p><pre class="programlisting">std::cout &lt;&lt; v &lt;&lt; std::endl;</pre><p>While use of <tt class="computeroutput">get</tt> is perfectly acceptable in this trivial
  109. example, <tt class="computeroutput">get</tt> generally suffers from several significant
  110. shortcomings. For instance, if we were to write a function accepting a
  111. <tt class="computeroutput">variant&lt;int, std::string&gt;</tt>, we would not know whether
  112. the passed <tt class="computeroutput">variant</tt> contained an <tt class="computeroutput">int</tt> or a
  113. <tt class="computeroutput">std::string</tt>. If we insisted upon continued use of
  114. <tt class="computeroutput">get</tt>, we would need to query the <tt class="computeroutput">variant</tt> for its
  115. contained type. The following function, which "doubles" the
  116. content of the given <tt class="computeroutput">variant</tt>, demonstrates this approach:
  117. </p><pre class="programlisting">void times_two( boost::variant&lt; int, std::string &gt; &amp; operand )
  118. {
  119. if ( int* pi = <a href="id2493238-bb.html" title="Function get">boost::get</a>&lt;int&gt;( &amp;v ) )
  120. *pi *= 2;
  121. else if ( std::string* pstr = <a href="id2493238-bb.html" title="Function get">boost::get</a>&lt;std::string&gt;( &amp;v ) )
  122. *pstr += *pstr;
  123. }</pre><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. <tt class="computeroutput">times_two</tt> to operate on a <tt class="computeroutput">variant</tt> with additional
  127. bounded types. Specifically, let's add
  128. <tt class="computeroutput">std::complex&lt;double&gt;</tt> to the set. Clearly, we would need
  129. to at least change the function declaration:
  130. </p><pre class="programlisting">void times_two( boost::variant&lt; int, std::string, std::complex&lt;double&gt; &gt; &amp; operand )
  131. {
  132. // as above...?
  133. }</pre><p>Of course, additional changes are required, for currently if the passed
  134. <tt class="computeroutput">variant</tt> in fact contained a <tt class="computeroutput">std::complex</tt> value,
  135. <tt class="computeroutput">times_two</tt> would silently return -- without any of the desired
  136. side-effects and without any error. In this case, the fix is obvious. But in
  137. more complicated programs, it could take considerable time to identify and
  138. locate the error in the first place.</p><p>Thus, real-world use of <tt class="computeroutput">variant</tt> typically demands an access
  139. mechanism more robust than <tt class="computeroutput">get</tt>. For this reason,
  140. <tt class="computeroutput">variant</tt> supports compile-time checked
  141. <span class="bold"><b>visitation</b></span> via
  142. <tt class="computeroutput"><a href="id2557051-bb.html" title="Function apply_visitor">apply_visitor</a></tt>. Visitation requires
  143. that the programmer explicitly handle (or ignore) each bounded type. Failure
  144. to do so results in a compile-time error.</p><p>Visitation of a <tt class="computeroutput">variant</tt> requires a visitor object. The
  145. following demonstrates one such implementation of a visitor implementating
  146. behavior identical to <tt class="computeroutput">times_two</tt>:
  147. </p><pre class="programlisting">class times_two_visitor
  148. : public <a href="class.boost.static_visitor.html" title="Class template static_visitor">boost::static_visitor</a>&lt;&gt;
  149. {
  150. public:
  151. void operator()(int &amp; i) const
  152. {
  153. i *= 2;
  154. }
  155. void operator()(std::string &amp; str) const
  156. {
  157. str += str;
  158. }
  159. };</pre><p>With the implementation of the above visitor, we can then apply it to
  160. <tt class="computeroutput">v</tt>, as seen in the following:
  161. </p><pre class="programlisting"><a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( times_two_visitor(), v );</pre><p>As expected, the content of <tt class="computeroutput">v</tt> is now a
  162. <tt class="computeroutput">std::string</tt> equal to <tt class="computeroutput">"hello world! hello world! "</tt>.
  163. (We'll skip the verification this time.)</p><p>In addition to enhanced robustness, visitation provides another
  164. important advantage over <tt class="computeroutput">get</tt>: the ability to write generic
  165. visitors. For instance, the following visitor will "double" the
  166. content of <span class="emphasis"><em>any</em></span><tt class="computeroutput">variant</tt> (provided its
  167. bounded types each support operator+=):
  168. </p><pre class="programlisting">class times_two_generic
  169. : public <a href="class.boost.static_visitor.html" title="Class template static_visitor">boost::static_visitor</a>&lt;&gt;
  170. {
  171. public:
  172. template &lt;typename T&gt;
  173. void operator()( T &amp; operand ) const
  174. {
  175. operand += operand;
  176. }
  177. };</pre><p>Again, <tt class="computeroutput">apply_visitor</tt> sets the wheels in motion:
  178. </p><pre class="programlisting"><a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( times_two_generic(), v );</pre><p>While the initial setup costs of visitation may exceed that required for
  179. <tt class="computeroutput">get</tt>, the benefits quickly become significant. Before concluding
  180. this section, we should explore one last benefit of visitation with
  181. <tt class="computeroutput">apply_visitor</tt>:
  182. <span class="bold"><b>delayed visitation</b></span>. Namely, a special form
  183. of <tt class="computeroutput">apply_visitor</tt> is available that does not immediately apply
  184. the given visitor to any <tt class="computeroutput">variant</tt> but rather returns a function
  185. object that operates on any <tt class="computeroutput">variant</tt> given to it. This behavior
  186. is particularly useful when operating on sequences of <tt class="computeroutput">variant</tt>
  187. type, as the following demonstrates:
  188. </p><pre class="programlisting">std::vector&lt; <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt;int, std::string&gt; &gt; vec;
  189. vec.push_back( 21 );
  190. vec.push_back( "hello " );
  191. times_two_generic visitor;
  192. std::for_each(
  193. vec.begin(), vec.end()
  194. , <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>(visitor)
  195. );</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="variant.tutorial.advanced"></a>Advanced Topics</h4></div></div><div></div></div><div class="toc"><dl><dt><a href="variant.tutorial.html#variant.tutorial.preprocessor">Preprocessor macros</a></dt><dt><a href="variant.tutorial.html#variant.tutorial.over-sequence">Using a type sequence to specify bounded types</a></dt><dt><a href="variant.tutorial.html#variant.tutorial.recursive">Recursive variant types</a></dt><dt><a href="variant.tutorial.html#variant.tutorial.binary-visitation">Binary visitation</a></dt></dl></div><p>This section discusses several features of the library often required
  196. for advanced uses of <tt class="computeroutput">variant</tt>. Unlike in the above section, each
  197. feature presented below is largely independent of the others. Accordingly,
  198. this section is not necessarily intended to be read linearly or in its
  199. entirety.</p><div class="section" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="variant.tutorial.preprocessor"></a>Preprocessor macros</h5></div></div><div></div></div><p>While the <tt class="computeroutput">variant</tt> class template's variadic parameter
  200. list greatly simplifies use for specific instantiations of the template,
  201. it significantly complicates use for generic instantiations. For instance,
  202. while it is immediately clear how one might write a function accepting a
  203. specific <tt class="computeroutput">variant</tt> instantiation, say
  204. <tt class="computeroutput">variant&lt;int, std::string&gt;</tt>, it is less clear how one
  205. might write a function accepting any given <tt class="computeroutput">variant</tt>.</p><p>Due to the lack of support for true variadic template parameter lists
  206. in the C++98 standard, the preprocessor is needed. While the
  207. <a href="../../libs/preprocessor/index.html" target="_top">Preprocessor</a> library provides a general and
  208. powerful solution, the need to repeat
  209. <tt class="computeroutput"><a href="BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES">BOOST_VARIANT_LIMIT_TYPES</a></tt>
  210. unnecessarily clutters otherwise simple code. Therefore, for common
  211. use-cases, this library provides its own macro
  212. <tt class="computeroutput"><span class="bold"><b><a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a></b></span></tt>.</p><p>This macro simplifies for the user the process of declaring
  213. <tt class="computeroutput">variant</tt> types in function templates or explicit partial
  214. specializations of class templates, as shown in the following:
  215. </p><pre class="programlisting">// general cases
  216. template &lt;typename T&gt; void some_func(const T &amp;);
  217. template &lt;typename T&gt; class some_class;
  218. // function template overload
  219. template &lt;<a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a>(typename T)&gt;
  220. void some_func(const <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt;<a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a>(T)&gt; &amp;);
  221. // explicit partial specialization
  222. template &lt;<a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a>(typename T)&gt;
  223. class some_class&lt; <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt;<a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a>(T)&gt; &gt;;</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="variant.tutorial.over-sequence"></a>Using a type sequence to specify bounded types</h5></div></div><div></div></div><p>While convenient for typical uses, the <tt class="computeroutput">variant</tt> class
  224. template's variadic template parameter list is limiting in two significant
  225. dimensions. First, due to the lack of support for true variadic template
  226. parameter lists in C++, the number of parameters must be limited to some
  227. implementation-defined maximum (namely,
  228. <tt class="computeroutput"><a href="BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES">BOOST_VARIANT_LIMIT_TYPES</a></tt>).
  229. Second, the nature of parameter lists in general makes compile-time
  230. manipulation of the lists excessively difficult.</p><p>To solve these problems,
  231. <tt class="computeroutput">make_variant_over&lt; <span class="emphasis"><em>Sequence</em></span> &gt;</tt>
  232. exposes a <tt class="computeroutput">variant</tt> whose bounded types are the elements of
  233. <tt class="computeroutput">Sequence</tt> (where <tt class="computeroutput">Sequence</tt> is any type fulfilling
  234. the requirements of <a href="../../libs/mpl/index.html" target="_top">MPL</a>'s
  235. <span class="emphasis"><em>Sequence</em></span> concept). For instance,
  236. </p><pre class="programlisting">typedef mpl::vector&lt; std::string &gt; types_initial;
  237. typedef mpl::push_front&lt; types_initial, int &gt;::type types;
  238. <a href="class.boost.make_variant_over.html" title="Class template make_variant_over">boost::make_variant_over</a>&lt; types &gt;::type v1;</pre><p>
  239. behaves equivalently to
  240. </p><pre class="programlisting"><a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt; int, std::string &gt; v2;</pre><p><span class="bold"><b>Portability</b></span>: Unfortunately, due to
  241. standard conformance issues in several compilers,
  242. <tt class="computeroutput">make_variant_over</tt> is not universally available. On these
  243. compilers the library indicates its lack of support for the syntax via the
  244. definition of the preprocessor symbol
  245. <tt 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></tt>.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="variant.tutorial.recursive"></a>Recursive <tt class="computeroutput">variant</tt> types</h5></div></div><div></div></div><div class="toc"><dl><dt><a href="variant.tutorial.html#variant.tutorial.recursive.recursive-wrapper">Recursive types with recursive_wrapper</a></dt><dt><a href="variant.tutorial.html#variant.tutorial.recursive.recursive-variant">Recursive types with make_recursive_variant</a></dt></dl></div><p>Recursive types facilitate the construction of complex semantics from
  246. simple syntax. For instance, nearly every programmer is familiar with the
  247. canonical definition of a linked list implementation, whose simple
  248. definition allows sequences of unlimited length:
  249. </p><pre class="programlisting">template &lt;typename T&gt;
  250. struct list_node
  251. {
  252. T data;
  253. list_node * next;
  254. };</pre><p>The nature of <tt class="computeroutput">variant</tt> as a generic class template
  255. unfortunately precludes the straightforward construction of recursive
  256. <tt class="computeroutput">variant</tt> types. Consider the following attempt to construct
  257. a structure for simple mathematical expressions:
  258. </p><pre class="programlisting">struct add;
  259. struct sub;
  260. template &lt;typename OpTag&gt; struct binary_op;
  261. typedef <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt;
  262. int
  263. , binary_op&lt;add&gt;
  264. , binary_op&lt;sub&gt;
  265. &gt; expression;
  266. template &lt;typename OpTag&gt;
  267. struct binary_op
  268. {
  269. expression left; // <span class="emphasis"><em>variant instantiated here...</em></span>
  270. expression right;
  271. binary_op( const expression &amp; lhs, const expression &amp; rhs )
  272. : left(lhs), right(rhs)
  273. {
  274. }
  275. }; // <span class="emphasis"><em>...but binary_op not complete until here!</em></span></pre><p>While well-intentioned, the above approach will not compile because
  276. <tt class="computeroutput">binary_op</tt> is still incomplete when the <tt class="computeroutput">variant</tt>
  277. type <tt class="computeroutput">expression</tt> is instantiated. Further, the approach suffers
  278. from a more significant logical flaw: even if C++ syntax were different
  279. such that the above example could be made to "work,"
  280. <tt class="computeroutput">expression</tt> would need to be of infinite size, which is
  281. clearly impossible.</p><p>To overcome these difficulties, <tt class="computeroutput">variant</tt> includes special
  282. support for the
  283. <tt class="computeroutput"><a href="class.boost.recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a></tt> class
  284. template, which breaks the circular dependency at the heart of these
  285. problems. Further,
  286. <tt class="computeroutput"><a href="class.boost.make_recursive_variant.html" title="Class template make_recursive_variant">boost::make_recursive_variant</a></tt> provides
  287. a more convenient syntax for declaring recursive <tt class="computeroutput">variant</tt>
  288. types. Tutorials for use of these facilities is described in
  289. <a href="variant.tutorial.html#variant.tutorial.recursive.recursive-wrapper" title="Recursive types with recursive_wrapper">the section called &#8220;Recursive types with recursive_wrapper&#8221;</a> and
  290. <a href="variant.tutorial.html#variant.tutorial.recursive.recursive-variant" title="Recursive types with make_recursive_variant">the section called &#8220;Recursive types with make_recursive_variant&#8221;</a>.</p><div class="section" lang="en"><div class="titlepage"><div><div><h6 class="title"><a name="variant.tutorial.recursive.recursive-wrapper"></a>Recursive types with <tt class="computeroutput">recursive_wrapper</tt></h6></div></div><div></div></div><p>The following example demonstrates how <tt class="computeroutput">recursive_wrapper</tt>
  291. could be used to solve the problem presented in
  292. <a href="variant.tutorial.html#variant.tutorial.recursive" title="Recursive variant types">the section called &#8220;Recursive variant types&#8221;</a>:
  293. </p><pre class="programlisting">typedef <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt;
  294. int
  295. , <a href="class.boost.recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a>&lt; binary_op&lt;add&gt; &gt;
  296. , <a href="class.boost.recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a>&lt; binary_op&lt;sub&gt; &gt;
  297. &gt; expression;</pre><p>Because <tt class="computeroutput">variant</tt> provides special support for
  298. <tt class="computeroutput">recursive_wrapper</tt>, clients may treat the resultant
  299. <tt class="computeroutput">variant</tt> as though the wrapper were not present. This is seen
  300. in the implementation of the following visitor, which calculates the value
  301. of an <tt class="computeroutput">expression</tt> without any reference to
  302. <tt class="computeroutput">recursive_wrapper</tt>:
  303. </p><pre class="programlisting">class calculator : public <a href="class.boost.static_visitor.html" title="Class template static_visitor">boost::static_visitor&lt;int&gt;</a>
  304. {
  305. public:
  306. int operator()(int value) const
  307. {
  308. return value;
  309. }
  310. int operator()(const binary_op&lt;add&gt; &amp; binary) const
  311. {
  312. return <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( calculator(), binary.left )
  313. + <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( calculator(), binary.right );
  314. }
  315. int operator()(const binary_op&lt;sub&gt; &amp; binary) const
  316. {
  317. return <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( calculator(), binary.left )
  318. - <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( calculator(), binary.right );
  319. }
  320. };</pre><p>Finally, we can demonstrate <tt class="computeroutput">expression</tt> in action:
  321. </p><pre class="programlisting">void f()
  322. {
  323. // result = ((7-3)+8) = 12
  324. expression result(
  325. binary_op&lt;add&gt;(
  326. binary_op&lt;sub&gt;(7,3)
  327. , 8
  328. )
  329. );
  330. assert( <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>(calculator(),result) == 12 );
  331. }</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h6 class="title"><a name="variant.tutorial.recursive.recursive-variant"></a>Recursive types with <tt class="computeroutput">make_recursive_variant</tt></h6></div></div><div></div></div><p>For some applications of recursive <tt class="computeroutput">variant</tt> types, a user
  332. may be able to sacrifice the full flexibility of using
  333. <tt class="computeroutput">recursive_wrapper</tt> with <tt class="computeroutput">variant</tt> for the following
  334. convenient syntax:
  335. </p><pre class="programlisting">typedef <a href="class.boost.make_recursive_variant.html" title="Class template make_recursive_variant">boost::make_recursive_variant</a>&lt;
  336. int
  337. , std::vector&lt; boost::recursive_variant_ &gt;
  338. &gt;::type int_tree_t;</pre><p>Use of the resultant <tt class="computeroutput">variant</tt> type is as expected:
  339. </p><pre class="programlisting">std::vector&lt; int_tree_t &gt; subresult;
  340. subresult.push_back(3);
  341. subresult.push_back(5);
  342. std::vector&lt; int_tree_t &gt; result;
  343. result.push_back(1);
  344. result.push_back(subresult);
  345. result.push_back(7);
  346. int_tree_t var(result);</pre><p>To be clear, one might represent the resultant content of
  347. <tt class="computeroutput">var</tt> as <tt class="computeroutput">( 1 ( 3 5 ) 7 )</tt>.</p><p>Finally, note that a type sequence can be used to specify the bounded
  348. types of a recursive <tt class="computeroutput">variant</tt> via the use of
  349. <tt class="computeroutput"><a href="class.boost.make_recursive_variant_over.html" title="Class template make_recursive_variant_over">boost::make_recursive_variant_over</a></tt>,
  350. whose semantics are the same as <tt class="computeroutput">make_variant_over</tt> (which is
  351. described in <a href="variant.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><p><span class="bold"><b>Portability</b></span>: Unfortunately, due to
  352. standard conformance issues in several compilers,
  353. <tt class="computeroutput">make_recursive_variant</tt> is not universally supported. On these
  354. compilers the library indicates its lack of support via the definition
  355. of the preprocessor symbol
  356. <tt 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></tt>.
  357. Thus, unless working with highly-conformant compilers, maximum portability
  358. will be achieved by instead using <tt class="computeroutput">recursive_wrapper</tt>, as
  359. described in
  360. <a href="variant.tutorial.html#variant.tutorial.recursive.recursive-wrapper" title="Recursive types with recursive_wrapper">the section called &#8220;Recursive types with recursive_wrapper&#8221;</a>.</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="variant.tutorial.binary-visitation"></a>Binary visitation</h5></div></div><div></div></div><p>As the tutorial above demonstrates, visitation is a powerful mechanism
  361. for manipulating <tt class="computeroutput">variant</tt> content. Binary visitation further
  362. extends the power and flexibility of visitation by allowing simultaneous
  363. visitation of the content of two different <tt class="computeroutput">variant</tt>
  364. objects.</p><p>Notably this feature requires that binary visitors are incompatible
  365. with the visitor objects discussed in the tutorial above, as they must
  366. operate on two arguments. The following demonstrates the implementation of
  367. a binary visitor:
  368. </p><pre class="programlisting">class are_strict_equals
  369. : public <a href="class.boost.static_visitor.html" title="Class template static_visitor">boost::static_visitor</a>&lt;bool&gt;
  370. {
  371. public:
  372. template &lt;typename T, typename U&gt;
  373. bool operator()( const T &amp;, const U &amp; )
  374. {
  375. return false; // cannot compare different types
  376. }
  377. template &lt;typename T&gt;
  378. bool operator()( const T &amp; lhs, const T &amp; rhs )
  379. {
  380. return lhs == rhs;
  381. }
  382. };</pre><p>As expected, the visitor is applied to two <tt class="computeroutput">variant</tt>
  383. arguments by means of <tt class="computeroutput">apply_visitor</tt>:
  384. </p><pre class="programlisting"><a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt; int, std::string &gt; v1( "hello" );
  385. <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt; double, std::string &gt; v2( "hello" );
  386. assert( <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>(are_strict_equals(), v1, v2) );
  387. <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt; int, const char * &gt; v3( "hello" );
  388. assert( !<a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>(are_strict_equals(), v1, v3) );</pre><p>Finally, we must note that the function object returned from the
  389. "delayed" form of
  390. <tt class="computeroutput"><a href="id2557051-bb.html" title="Function apply_visitor">apply_visitor</a></tt> also supports
  391. binary visitation, as the following demonstrates:
  392. </p><pre class="programlisting">typedef <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>&lt;double, std::string&gt; my_variant;
  393. std::vector&lt; my_variant &gt; seq1;
  394. seq1.push_back("pi is close to ");
  395. seq1.push_back(3.14);
  396. std::list&lt; my_variant &gt; seq2;
  397. seq2.push_back("pi is close to ");
  398. seq2.push_back(3.14);
  399. are_strict_equals visitor;
  400. assert( std::equal(
  401. v1.begin(), v1.end(), v2.begin()
  402. , <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( visitor )
  403. ) );</pre></div></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"><small>Last revised: , at GMT</small></td><td align="right"><small>Copyright © 2002, 2003 Eric Friedman, Itay Maman</small></td></tr></table><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="variant.html"><img src="images/prev.png" alt="Prev"></a> </td><td width="20%" align="center"><a accesskey="u" href="variant.html"><img src="images/up.png" alt="Up"></a></td><td width="40%" align="right"> <a accesskey="n" href="variant.reference.html"><img src="images/next.png" alt="Next"></a></td></tr><tr><td width="40%" align="left" valign="top">Boost.Variant </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a></td><td width="40%" align="right" valign="top"> Reference</td></tr></table></div></body></html>
粤ICP备19079148号