| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- <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<void>"><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<<"><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="
- BoostBook element class-specialization"><link rel="refentry" href="boostbook.dtd.link-test.html" title="
- BoostBook element link-test"><link rel="refentry" href="boostbook.dtd.link-fail-test.html" title="
- BoostBook element link-fail-test"><link rel="refentry" href="boostbook.dtd.typedef.html" title="
- BoostBook element typedef"><link rel="refentry" href="boostbook.dtd.static-constant.html" title="
- BoostBook element static-constant"><link rel="refentry" href="boostbook.dtd.code.html" title="
- BoostBook element code"><link rel="refentry" href="boostbook.dtd.destructor.html" title="
- BoostBook element destructor"><link rel="refentry" href="boostbook.dtd.template-type-parameter.html" title="
- BoostBook element template-type-parameter"><link rel="refentry" href="boostbook.dtd.description.html" title="
- BoostBook element description"><link rel="refentry" href="boostbook.dtd.librarylist.html" title="
- BoostBook element librarylist"><link rel="refentry" href="boostbook.dtd.library-reference.html" title="
- BoostBook element library-reference"><link rel="refentry" href="boostbook.dtd.boostbook.html" title="
- BoostBook element boostbook"><link rel="refentry" href="boostbook.dtd.union.html" title="
- BoostBook element union"><link rel="refentry" href="boostbook.dtd.inherit.html" title="
- BoostBook element inherit"><link rel="refentry" href="boostbook.dtd.template-varargs.html" title="
- BoostBook element template-varargs"><link rel="refentry" href="boostbook.dtd.source.html" title="
- BoostBook element source"><link rel="refentry" href="boostbook.dtd.function.html" title="
- BoostBook element function"><link rel="refentry" href="boostbook.dtd.postconditions.html" title="
- BoostBook element postconditions"><link rel="refentry" href="boostbook.dtd.compile-test.html" title="
- BoostBook element compile-test"><link rel="refentry" href="boostbook.dtd.method.html" title="
- BoostBook element method"><link rel="refentry" href="boostbook.dtd.snippet.html" title="
- BoostBook element snippet"><link rel="refentry" href="boostbook.dtd.constructor.html" title="
- BoostBook element constructor"><link rel="refentry" href="boostbook.dtd.namespace.html" title="
- BoostBook element namespace"><link rel="refentry" href="boostbook.dtd.if-fails.html" title="
- BoostBook element if-fails"><link rel="refentry" href="boostbook.dtd.free-function-group.html" title="
- BoostBook element free-function-group"><link rel="refentry" href="boostbook.dtd.functionname.html" title="
- BoostBook element functionname"><link rel="refentry" href="boostbook.dtd.librarycategory.html" title="
- BoostBook element librarycategory"><link rel="refentry" href="boostbook.dtd.notes.html" title="
- BoostBook element notes"><link rel="refentry" href="boostbook.dtd.data-member.html" title="
- BoostBook element data-member"><link rel="refentry" href="boostbook.dtd.specialization.html" title="
- BoostBook element specialization"><link rel="refentry" href="boostbook.dtd.union-specialization.html" title="
- BoostBook element union-specialization"><link rel="refentry" href="boostbook.dtd.throws.html" title="
- BoostBook element throws"><link rel="refentry" href="boostbook.dtd.template-arg.html" title="
- BoostBook element template-arg"><link rel="refentry" href="boostbook.dtd.method-group.html" title="
- BoostBook element method-group"><link rel="refentry" href="boostbook.dtd.requirement.html" title="
- BoostBook element requirement"><link rel="refentry" href="boostbook.dtd.precondition.html" title="
- BoostBook element precondition"><link rel="refentry" href="boostbook.dtd.paramtype.html" title="
- BoostBook element paramtype"><link rel="refentry" href="boostbook.dtd.using-class.html" title="
- BoostBook element using-class"><link rel="refentry" href="boostbook.dtd.run-test.html" title="
- BoostBook element run-test"><link rel="refentry" href="boostbook.dtd.librarypurpose.html" title="
- BoostBook element librarypurpose"><link rel="refentry" href="boostbook.dtd.copy-assignment.html" title="
- BoostBook element copy-assignment"><link rel="refentry" href="boostbook.dtd.run-fail-test.html" title="
- BoostBook element run-fail-test"><link rel="refentry" href="boostbook.dtd.template.html" title="
- BoostBook element template"><link rel="refentry" href="boostbook.dtd.compile-fail-test.html" title="
- BoostBook element compile-fail-test"><link rel="refentry" href="boostbook.dtd.returns.html" title="
- BoostBook element returns"><link rel="refentry" href="boostbook.dtd.default.html" title="
- BoostBook element default"><link rel="refentry" href="boostbook.dtd.parameter.html" title="
- BoostBook element parameter"><link rel="refentry" href="boostbook.dtd.signature.html" title="
- BoostBook element signature"><link rel="refentry" href="boostbook.dtd.overloaded-function.html" title="
- BoostBook element overloaded-function"><link rel="refentry" href="boostbook.dtd.class.html" title="
- BoostBook element class"><link rel="refentry" href="boostbook.dtd.librarycategorydef.html" title="
- BoostBook element librarycategorydef"><link rel="refentry" href="boostbook.dtd.type.html" title="
- BoostBook element type"><link rel="refentry" href="boostbook.dtd.enumvalue.html" title="
- BoostBook element enumvalue"><link rel="refentry" href="boostbook.dtd.overloaded-method.html" title="
- BoostBook element overloaded-method"><link rel="refentry" href="boostbook.dtd.programlisting.html" title="
- BoostBook element programlisting"><link rel="refentry" href="boostbook.dtd.complexity.html" title="
- BoostBook element complexity"><link rel="refentry" href="boostbook.dtd.purpose.html" title="
- BoostBook element purpose"><link rel="refentry" href="boostbook.dtd.template-nontype-parameter.html" title="
- BoostBook element template-nontype-parameter"><link rel="refentry" href="boostbook.dtd.library.html" title="
- BoostBook element library"><link rel="refentry" href="boostbook.dtd.librarycategorylist.html" title="
- BoostBook element librarycategorylist"><link rel="refentry" href="boostbook.dtd.using-namespace.html" title="
- BoostBook element using-namespace"><link rel="refentry" href="boostbook.dtd.struct-specialization.html" title="
- BoostBook element struct-specialization"><link rel="refentry" href="boostbook.dtd.struct.html" title="
- BoostBook element struct"><link rel="refentry" href="boostbook.dtd.lib.html" title="
- BoostBook element lib"><link rel="refentry" href="boostbook.dtd.enum.html" title="
- BoostBook element enum"><link rel="refentry" href="boostbook.dtd.requires.html" title="
- BoostBook element requires"><link rel="refentry" href="boostbook.dtd.effects.html" title="
- BoostBook element effects"><link rel="refentry" href="boostbook.dtd.libraryname.html" title="
- BoostBook element libraryname"><link rel="refentry" href="boostbook.dtd.libraryinfo.html" title="
- BoostBook element libraryinfo"><link rel="refentry" href="boostbook.dtd.testsuite.html" title="
- BoostBook element testsuite"><link rel="refentry" href="boostbook.dtd.header.html" title="
- BoostBook element header"><link rel="refentry" href="boostbook.dtd.rationale.html" title="
- 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
- instantiating the <tt class="computeroutput"><a href="class.boost.variant.html" title="Class template variant">boost::variant</a></tt> class
- template with the desired types. These types are called
- <span class="bold"><b>bounded types</b></span> and are subject to the
- requirements of the
- <a href="variant.reference.html#variant.concepts.bounded-type" title="BoundedType"><span class="emphasis"><em>BoundedType</em></span></a>
- concept. Any number of bounded types may be specified, up to some
- implementation-defined limit (see
- <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
- <tt class="computeroutput">int</tt> and <tt class="computeroutput">std::string</tt>:
- </p><pre class="programlisting"><a href="class.boost.variant.html" title="Class template variant">boost::variant</a>< int, std::string > v;</pre><p>By default, a <tt class="computeroutput">variant</tt> default-constructs its first
- bounded type, so <tt class="computeroutput">v</tt> initially contains <tt class="computeroutput">int(0)</tt>. If
- this is not desired, or if the first bounded type is not
- default-constructible, a <tt class="computeroutput">variant</tt> can be constructed
- directly from any value convertible to one of its bounded types. Similarly,
- a <tt class="computeroutput">variant</tt> can be assigned any value convertible to one of its
- bounded types, as demonstrated in the following:
- </p><pre class="programlisting">v = "hello";</pre><p>Now <tt class="computeroutput">v</tt> contains a <tt class="computeroutput">std::string</tt> equal to
- <tt class="computeroutput">"hello"</tt>. We can demonstrate this by
- <span class="bold"><b>streaming</b></span><tt class="computeroutput">v</tt> to standard
- output:
- </p><pre class="programlisting">std::cout << v << std::endl;</pre><p>Usually though, we would like to do more with the content of a
- <tt class="computeroutput">variant</tt> than streaming. Thus, we need some way to access the
- contained value. There are two ways to accomplish this:
- <tt class="computeroutput"><a href="id2557051-bb.html" title="Function apply_visitor">apply_visitor</a></tt>, which is safest
- and very powerful, and
- <tt class="computeroutput"><a href="id2493238-bb.html" title="Function get">get</a><T></tt>, which is
- sometimes more convenient to use.</p><p>For instance, suppose we wanted to concatenate to the string contained
- in <tt class="computeroutput">v</tt>. With <span class="bold"><b>value retrieval</b></span>
- by <tt class="computeroutput"><a href="id2493238-bb.html" title="Function get">get</a></tt>, this may be accomplished
- quite simply, as seen in the following:
- </p><pre class="programlisting">std::string& str = <a href="id2493238-bb.html" title="Function get">boost::get</a><std::string>(v);
- str += " world! ";</pre><p>As desired, the <tt class="computeroutput">std::string</tt> contained by <tt class="computeroutput">v</tt> now
- is equal to <tt class="computeroutput">"hello world! "</tt>. Again, we can demonstrate this by
- streaming <tt class="computeroutput">v</tt> to standard output:
- </p><pre class="programlisting">std::cout << v << std::endl;</pre><p>While use of <tt class="computeroutput">get</tt> is perfectly acceptable in this trivial
- example, <tt class="computeroutput">get</tt> generally suffers from several significant
- shortcomings. For instance, if we were to write a function accepting a
- <tt class="computeroutput">variant<int, std::string></tt>, we would not know whether
- the passed <tt class="computeroutput">variant</tt> contained an <tt class="computeroutput">int</tt> or a
- <tt class="computeroutput">std::string</tt>. If we insisted upon continued use of
- <tt class="computeroutput">get</tt>, we would need to query the <tt class="computeroutput">variant</tt> for its
- contained type. The following function, which "doubles" the
- content of the given <tt class="computeroutput">variant</tt>, demonstrates this approach:
- </p><pre class="programlisting">void times_two( boost::variant< int, std::string > & operand )
- {
- if ( int* pi = <a href="id2493238-bb.html" title="Function get">boost::get</a><int>( &v ) )
- *pi *= 2;
- else if ( std::string* pstr = <a href="id2493238-bb.html" title="Function get">boost::get</a><std::string>( &v ) )
- *pstr += *pstr;
- }</pre><p>However, such code is quite brittle, and without careful attention will
- likely lead to the introduction of subtle logical errors detectable only at
- runtime. For instance, consider if we wished to extend
- <tt class="computeroutput">times_two</tt> to operate on a <tt class="computeroutput">variant</tt> with additional
- bounded types. Specifically, let's add
- <tt class="computeroutput">std::complex<double></tt> to the set. Clearly, we would need
- to at least change the function declaration:
- </p><pre class="programlisting">void times_two( boost::variant< int, std::string, std::complex<double> > & operand )
- {
- // as above...?
- }</pre><p>Of course, additional changes are required, for currently if the passed
- <tt class="computeroutput">variant</tt> in fact contained a <tt class="computeroutput">std::complex</tt> value,
- <tt class="computeroutput">times_two</tt> would silently return -- without any of the desired
- side-effects and without any error. In this case, the fix is obvious. But in
- more complicated programs, it could take considerable time to identify and
- locate the error in the first place.</p><p>Thus, real-world use of <tt class="computeroutput">variant</tt> typically demands an access
- mechanism more robust than <tt class="computeroutput">get</tt>. For this reason,
- <tt class="computeroutput">variant</tt> supports compile-time checked
- <span class="bold"><b>visitation</b></span> via
- <tt class="computeroutput"><a href="id2557051-bb.html" title="Function apply_visitor">apply_visitor</a></tt>. Visitation requires
- that the programmer explicitly handle (or ignore) each bounded type. Failure
- to do so results in a compile-time error.</p><p>Visitation of a <tt class="computeroutput">variant</tt> requires a visitor object. The
- following demonstrates one such implementation of a visitor implementating
- behavior identical to <tt class="computeroutput">times_two</tt>:
- </p><pre class="programlisting">class times_two_visitor
- : public <a href="class.boost.static_visitor.html" title="Class template static_visitor">boost::static_visitor</a><>
- {
- public:
- void operator()(int & i) const
- {
- i *= 2;
- }
- void operator()(std::string & str) const
- {
- str += str;
- }
- };</pre><p>With the implementation of the above visitor, we can then apply it to
- <tt class="computeroutput">v</tt>, as seen in the following:
- </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
- <tt class="computeroutput">std::string</tt> equal to <tt class="computeroutput">"hello world! hello world! "</tt>.
- (We'll skip the verification this time.)</p><p>In addition to enhanced robustness, visitation provides another
- important advantage over <tt class="computeroutput">get</tt>: the ability to write generic
- visitors. For instance, the following visitor will "double" the
- content of <span class="emphasis"><em>any</em></span><tt class="computeroutput">variant</tt> (provided its
- bounded types each support operator+=):
- </p><pre class="programlisting">class times_two_generic
- : public <a href="class.boost.static_visitor.html" title="Class template static_visitor">boost::static_visitor</a><>
- {
- public:
- template <typename T>
- void operator()( T & operand ) const
- {
- operand += operand;
- }
- };</pre><p>Again, <tt class="computeroutput">apply_visitor</tt> sets the wheels in motion:
- </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
- <tt class="computeroutput">get</tt>, the benefits quickly become significant. Before concluding
- this section, we should explore one last benefit of visitation with
- <tt class="computeroutput">apply_visitor</tt>:
- <span class="bold"><b>delayed visitation</b></span>. Namely, a special form
- of <tt class="computeroutput">apply_visitor</tt> is available that does not immediately apply
- the given visitor to any <tt class="computeroutput">variant</tt> but rather returns a function
- object that operates on any <tt class="computeroutput">variant</tt> given to it. This behavior
- is particularly useful when operating on sequences of <tt class="computeroutput">variant</tt>
- type, as the following demonstrates:
- </p><pre class="programlisting">std::vector< <a href="class.boost.variant.html" title="Class template variant">boost::variant</a><int, std::string> > vec;
- vec.push_back( 21 );
- vec.push_back( "hello " );
- times_two_generic visitor;
- std::for_each(
- vec.begin(), vec.end()
- , <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>(visitor)
- );</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
- for advanced uses of <tt class="computeroutput">variant</tt>. Unlike in the above section, each
- feature presented below is largely independent of the others. Accordingly,
- this section is not necessarily intended to be read linearly or in its
- 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
- list greatly simplifies use for specific instantiations of the template,
- it significantly complicates use for generic instantiations. For instance,
- while it is immediately clear how one might write a function accepting a
- specific <tt class="computeroutput">variant</tt> instantiation, say
- <tt class="computeroutput">variant<int, std::string></tt>, it is less clear how one
- 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
- in the C++98 standard, the preprocessor is needed. While the
- <a href="../../libs/preprocessor/index.html" target="_top">Preprocessor</a> library provides a general and
- powerful solution, the need to repeat
- <tt class="computeroutput"><a href="BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES">BOOST_VARIANT_LIMIT_TYPES</a></tt>
- unnecessarily clutters otherwise simple code. Therefore, for common
- use-cases, this library provides its own macro
- <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
- <tt class="computeroutput">variant</tt> types in function templates or explicit partial
- specializations of class templates, as shown in the following:
- </p><pre class="programlisting">// general cases
- template <typename T> void some_func(const T &);
- template <typename T> class some_class;
- // function template overload
- template <<a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a>(typename T)>
- void some_func(const <a href="class.boost.variant.html" title="Class template variant">boost::variant</a><<a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a>(T)> &);
- // explicit partial specialization
- template <<a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a>(typename T)>
- class some_class< <a href="class.boost.variant.html" title="Class template variant">boost::variant</a><<a href="BOOST_VARIANT_ENUM_PARAMS.html" title="Macro BOOST_VARIANT_ENUM_PARAMS">BOOST_VARIANT_ENUM_PARAMS</a>(T)> >;</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
- template's variadic template parameter list is limiting in two significant
- dimensions. First, due to the lack of support for true variadic template
- parameter lists in C++, the number of parameters must be limited to some
- implementation-defined maximum (namely,
- <tt class="computeroutput"><a href="BOOST_VARIANT_LIMIT_TYPES.html" title="Macro BOOST_VARIANT_LIMIT_TYPES">BOOST_VARIANT_LIMIT_TYPES</a></tt>).
- Second, the nature of parameter lists in general makes compile-time
- manipulation of the lists excessively difficult.</p><p>To solve these problems,
- <tt class="computeroutput">make_variant_over< <span class="emphasis"><em>Sequence</em></span> ></tt>
- exposes a <tt class="computeroutput">variant</tt> whose bounded types are the elements of
- <tt class="computeroutput">Sequence</tt> (where <tt class="computeroutput">Sequence</tt> is any type fulfilling
- the requirements of <a href="../../libs/mpl/index.html" target="_top">MPL</a>'s
- <span class="emphasis"><em>Sequence</em></span> concept). For instance,
- </p><pre class="programlisting">typedef mpl::vector< std::string > types_initial;
- typedef mpl::push_front< types_initial, int >::type types;
- <a href="class.boost.make_variant_over.html" title="Class template make_variant_over">boost::make_variant_over</a>< types >::type v1;</pre><p>
- behaves equivalently to
- </p><pre class="programlisting"><a href="class.boost.variant.html" title="Class template variant">boost::variant</a>< int, std::string > v2;</pre><p><span class="bold"><b>Portability</b></span>: Unfortunately, due to
- standard conformance issues in several compilers,
- <tt class="computeroutput">make_variant_over</tt> is not universally available. On these
- compilers the library indicates its lack of support for the syntax via the
- definition of the preprocessor symbol
- <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
- simple syntax. For instance, nearly every programmer is familiar with the
- canonical definition of a linked list implementation, whose simple
- definition allows sequences of unlimited length:
- </p><pre class="programlisting">template <typename T>
- struct list_node
- {
- T data;
- list_node * next;
- };</pre><p>The nature of <tt class="computeroutput">variant</tt> as a generic class template
- unfortunately precludes the straightforward construction of recursive
- <tt class="computeroutput">variant</tt> types. Consider the following attempt to construct
- a structure for simple mathematical expressions:
- </p><pre class="programlisting">struct add;
- struct sub;
- template <typename OpTag> struct binary_op;
- typedef <a href="class.boost.variant.html" title="Class template variant">boost::variant</a><
- int
- , binary_op<add>
- , binary_op<sub>
- > expression;
- template <typename OpTag>
- struct binary_op
- {
- expression left; // <span class="emphasis"><em>variant instantiated here...</em></span>
- expression right;
- binary_op( const expression & lhs, const expression & rhs )
- : left(lhs), right(rhs)
- {
- }
- }; // <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
- <tt class="computeroutput">binary_op</tt> is still incomplete when the <tt class="computeroutput">variant</tt>
- type <tt class="computeroutput">expression</tt> is instantiated. Further, the approach suffers
- from a more significant logical flaw: even if C++ syntax were different
- such that the above example could be made to "work,"
- <tt class="computeroutput">expression</tt> would need to be of infinite size, which is
- clearly impossible.</p><p>To overcome these difficulties, <tt class="computeroutput">variant</tt> includes special
- support for the
- <tt class="computeroutput"><a href="class.boost.recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a></tt> class
- template, which breaks the circular dependency at the heart of these
- problems. Further,
- <tt class="computeroutput"><a href="class.boost.make_recursive_variant.html" title="Class template make_recursive_variant">boost::make_recursive_variant</a></tt> provides
- a more convenient syntax for declaring recursive <tt class="computeroutput">variant</tt>
- types. Tutorials for use of these facilities is described in
- <a href="variant.tutorial.html#variant.tutorial.recursive.recursive-wrapper" title="Recursive types with recursive_wrapper">the section called “Recursive types with recursive_wrapper”</a> and
- <a href="variant.tutorial.html#variant.tutorial.recursive.recursive-variant" title="Recursive types with make_recursive_variant">the section called “Recursive types with make_recursive_variant”</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>
- could be used to solve the problem presented in
- <a href="variant.tutorial.html#variant.tutorial.recursive" title="Recursive variant types">the section called “Recursive variant types”</a>:
- </p><pre class="programlisting">typedef <a href="class.boost.variant.html" title="Class template variant">boost::variant</a><
- int
- , <a href="class.boost.recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a>< binary_op<add> >
- , <a href="class.boost.recursive_wrapper.html" title="Class template recursive_wrapper">boost::recursive_wrapper</a>< binary_op<sub> >
- > expression;</pre><p>Because <tt class="computeroutput">variant</tt> provides special support for
- <tt class="computeroutput">recursive_wrapper</tt>, clients may treat the resultant
- <tt class="computeroutput">variant</tt> as though the wrapper were not present. This is seen
- in the implementation of the following visitor, which calculates the value
- of an <tt class="computeroutput">expression</tt> without any reference to
- <tt class="computeroutput">recursive_wrapper</tt>:
- </p><pre class="programlisting">class calculator : public <a href="class.boost.static_visitor.html" title="Class template static_visitor">boost::static_visitor<int></a>
- {
- public:
- int operator()(int value) const
- {
- return value;
- }
- int operator()(const binary_op<add> & binary) const
- {
- return <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( calculator(), binary.left )
- + <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( calculator(), binary.right );
- }
- int operator()(const binary_op<sub> & binary) const
- {
- return <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( calculator(), binary.left )
- - <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( calculator(), binary.right );
- }
- };</pre><p>Finally, we can demonstrate <tt class="computeroutput">expression</tt> in action:
-
- </p><pre class="programlisting">void f()
- {
- // result = ((7-3)+8) = 12
- expression result(
- binary_op<add>(
- binary_op<sub>(7,3)
- , 8
- )
- );
- assert( <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>(calculator(),result) == 12 );
- }</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
- may be able to sacrifice the full flexibility of using
- <tt class="computeroutput">recursive_wrapper</tt> with <tt class="computeroutput">variant</tt> for the following
- convenient syntax:
- </p><pre class="programlisting">typedef <a href="class.boost.make_recursive_variant.html" title="Class template make_recursive_variant">boost::make_recursive_variant</a><
- int
- , std::vector< boost::recursive_variant_ >
- >::type int_tree_t;</pre><p>Use of the resultant <tt class="computeroutput">variant</tt> type is as expected:
- </p><pre class="programlisting">std::vector< int_tree_t > subresult;
- subresult.push_back(3);
- subresult.push_back(5);
- std::vector< int_tree_t > result;
- result.push_back(1);
- result.push_back(subresult);
- result.push_back(7);
- int_tree_t var(result);</pre><p>To be clear, one might represent the resultant content of
- <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
- types of a recursive <tt class="computeroutput">variant</tt> via the use of
- <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>,
- whose semantics are the same as <tt class="computeroutput">make_variant_over</tt> (which is
- described in <a href="variant.tutorial.html#variant.tutorial.over-sequence" title="Using a type sequence to specify bounded types">the section called “Using a type sequence to specify bounded types”</a>).</p><p><span class="bold"><b>Portability</b></span>: Unfortunately, due to
- standard conformance issues in several compilers,
- <tt class="computeroutput">make_recursive_variant</tt> is not universally supported. On these
- compilers the library indicates its lack of support via the definition
- of the preprocessor symbol
- <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>.
- Thus, unless working with highly-conformant compilers, maximum portability
- will be achieved by instead using <tt class="computeroutput">recursive_wrapper</tt>, as
- described in
- <a href="variant.tutorial.html#variant.tutorial.recursive.recursive-wrapper" title="Recursive types with recursive_wrapper">the section called “Recursive types with recursive_wrapper”</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
- for manipulating <tt class="computeroutput">variant</tt> content. Binary visitation further
- extends the power and flexibility of visitation by allowing simultaneous
- visitation of the content of two different <tt class="computeroutput">variant</tt>
- objects.</p><p>Notably this feature requires that binary visitors are incompatible
- with the visitor objects discussed in the tutorial above, as they must
- operate on two arguments. The following demonstrates the implementation of
- a binary visitor:
- </p><pre class="programlisting">class are_strict_equals
- : public <a href="class.boost.static_visitor.html" title="Class template static_visitor">boost::static_visitor</a><bool>
- {
- public:
- template <typename T, typename U>
- bool operator()( const T &, const U & )
- {
- return false; // cannot compare different types
- }
- template <typename T>
- bool operator()( const T & lhs, const T & rhs )
- {
- return lhs == rhs;
- }
- };</pre><p>As expected, the visitor is applied to two <tt class="computeroutput">variant</tt>
- arguments by means of <tt class="computeroutput">apply_visitor</tt>:
- </p><pre class="programlisting"><a href="class.boost.variant.html" title="Class template variant">boost::variant</a>< int, std::string > v1( "hello" );
- <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>< double, std::string > v2( "hello" );
- assert( <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>(are_strict_equals(), v1, v2) );
- <a href="class.boost.variant.html" title="Class template variant">boost::variant</a>< int, const char * > v3( "hello" );
- 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
- "delayed" form of
- <tt class="computeroutput"><a href="id2557051-bb.html" title="Function apply_visitor">apply_visitor</a></tt> also supports
- binary visitation, as the following demonstrates:
- </p><pre class="programlisting">typedef <a href="class.boost.variant.html" title="Class template variant">boost::variant</a><double, std::string> my_variant;
- std::vector< my_variant > seq1;
- seq1.push_back("pi is close to ");
- seq1.push_back(3.14);
- std::list< my_variant > seq2;
- seq2.push_back("pi is close to ");
- seq2.push_back(3.14);
- are_strict_equals visitor;
- assert( std::equal(
- v1.begin(), v1.end(), v2.begin()
- , <a href="id2557051-bb.html" title="Function apply_visitor">boost::apply_visitor</a>( visitor )
- ) );</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>
|