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