[12] | 1 | <?xml version="1.0" encoding="utf-8"?> |
---|
| 2 | <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" |
---|
| 3 | "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> |
---|
| 4 | <section id="variant.intro"> |
---|
| 5 | <title>Introduction</title> |
---|
| 6 | |
---|
| 7 | <using-namespace name="boost"/> |
---|
| 8 | |
---|
| 9 | <section id="variant.abstract"> |
---|
| 10 | <title>Abstract</title> |
---|
| 11 | |
---|
| 12 | <para>The <code>variant</code> class template is a safe, generic, stack-based |
---|
| 13 | discriminated union container, offering a simple solution for manipulating an |
---|
| 14 | object from a heterogeneous set of types in a uniform manner. Whereas |
---|
| 15 | standard containers such as <code>std::vector</code> may be thought of as |
---|
| 16 | "<emphasis role="bold">multi-value, single type</emphasis>," |
---|
| 17 | <code>variant</code> is "<emphasis role="bold">multi-type, |
---|
| 18 | single value</emphasis>."</para> |
---|
| 19 | |
---|
| 20 | <para>Notable features of <code><classname>boost::variant</classname></code> |
---|
| 21 | include:</para> |
---|
| 22 | |
---|
| 23 | <itemizedlist> |
---|
| 24 | <listitem>Full value semantics, including adherence to standard |
---|
| 25 | overload resolution rules for conversion operations.</listitem> |
---|
| 26 | <listitem>Compile-time type-safe value visitation via |
---|
| 27 | <code><functionname>boost::apply_visitor</functionname></code>.</listitem> |
---|
| 28 | <listitem>Run-time checked explicit value retrieval via |
---|
| 29 | <code><functionname>boost::get</functionname></code>.</listitem> |
---|
| 30 | <listitem>Support for recursive variant types via both |
---|
| 31 | <code><classname>boost::make_recursive_variant</classname></code> and |
---|
| 32 | <code><classname>boost::recursive_wrapper</classname></code>.</listitem> |
---|
| 33 | <listitem>Efficient implementation -- stack-based when possible (see |
---|
| 34 | <xref linkend="variant.design.never-empty"/> for more details).</listitem> |
---|
| 35 | </itemizedlist> |
---|
| 36 | |
---|
| 37 | </section> |
---|
| 38 | |
---|
| 39 | <section id="variant.motivation"> |
---|
| 40 | <title>Motivation</title> |
---|
| 41 | |
---|
| 42 | <section id="variant.motivation.problem"> |
---|
| 43 | <title>Problem</title> |
---|
| 44 | |
---|
| 45 | <para>Many times, during the development of a C++ program, the |
---|
| 46 | programmer finds himself in need of manipulating several distinct |
---|
| 47 | types in a uniform manner. Indeed, C++ features direct language |
---|
| 48 | support for such types through its <code>union</code> |
---|
| 49 | keyword:</para> |
---|
| 50 | |
---|
| 51 | <programlisting>union { int i; double d; } u; |
---|
| 52 | u.d = 3.14; |
---|
| 53 | u.i = 3; // overwrites u.d (OK: u.d is a POD type)</programlisting> |
---|
| 54 | |
---|
| 55 | <para>C++'s <code>union</code> construct, however, is nearly |
---|
| 56 | useless in an object-oriented environment. The construct entered |
---|
| 57 | the language primarily as a means for preserving compatibility with |
---|
| 58 | C, which supports only POD (Plain Old Data) types, and so does not |
---|
| 59 | accept types exhibiting non-trivial construction or |
---|
| 60 | destruction:</para> |
---|
| 61 | |
---|
| 62 | <programlisting>union { |
---|
| 63 | int i; |
---|
| 64 | std::string s; // illegal: std::string is not a POD type! |
---|
| 65 | } u;</programlisting> |
---|
| 66 | |
---|
| 67 | <para>Clearly another approach is required. Typical solutions |
---|
| 68 | feature the dynamic-allocation of objects, which are subsequently |
---|
| 69 | manipulated through a common base type (often a virtual base class |
---|
| 70 | [<link linkend="variant.refs.hen01">Hen01</link>] |
---|
| 71 | or, more dangerously, a <code>void*</code>). Objects of |
---|
| 72 | concrete type may be then retrieved by way of a polymorphic downcast |
---|
| 73 | construct (e.g., <code>dynamic_cast</code>, |
---|
| 74 | <code><functionname>boost::any_cast</functionname></code>, etc.).</para> |
---|
| 75 | |
---|
| 76 | <para>However, solutions of this sort are highly error-prone, due |
---|
| 77 | to the following:</para> |
---|
| 78 | |
---|
| 79 | <itemizedlist> |
---|
| 80 | <listitem><emphasis>Downcast errors cannot be detected at |
---|
| 81 | compile-time.</emphasis> Thus, incorrect usage of downcast |
---|
| 82 | constructs will lead to bugs detectable only at run-time.</listitem> |
---|
| 83 | <listitem><emphasis>Addition of new concrete types may be |
---|
| 84 | ignored.</emphasis> If a new concrete type is added to the |
---|
| 85 | hierarchy, existing downcast code will continue to work as-is, |
---|
| 86 | wholly ignoring the new type. Consequently, the programmer must |
---|
| 87 | manually locate and modify code at numerous locations, which often |
---|
| 88 | results in run-time errors that are difficult to find.</listitem> |
---|
| 89 | </itemizedlist> |
---|
| 90 | |
---|
| 91 | <para>Furthermore, even when properly implemented, these solutions tend |
---|
| 92 | to incur a relatively significant abstraction penalty due to the use of |
---|
| 93 | the heap, virtual function calls, and polymorphic downcasts.</para> |
---|
| 94 | |
---|
| 95 | </section> |
---|
| 96 | |
---|
| 97 | <section id="variant.motivation.solution"> |
---|
| 98 | <title>Solution: A Motivating Example</title> |
---|
| 99 | |
---|
| 100 | <para>The <code><classname>boost::variant</classname></code> class template |
---|
| 101 | addresses these issues in a safe, straightforward, and efficient manner. The |
---|
| 102 | following example demonstrates how the class can be used:</para> |
---|
| 103 | |
---|
| 104 | <programlisting>#include "boost/variant.hpp" |
---|
| 105 | #include <iostream> |
---|
| 106 | |
---|
| 107 | class my_visitor : public <classname>boost::static_visitor</classname><int> |
---|
| 108 | { |
---|
| 109 | public: |
---|
| 110 | int operator()(int i) const |
---|
| 111 | { |
---|
| 112 | return i; |
---|
| 113 | } |
---|
| 114 | |
---|
| 115 | int operator()(const <classname>std::string</classname> & str) const |
---|
| 116 | { |
---|
| 117 | return str.length(); |
---|
| 118 | } |
---|
| 119 | }; |
---|
| 120 | |
---|
| 121 | int main() |
---|
| 122 | { |
---|
| 123 | <classname>boost::variant</classname>< int, std::string > u("hello world"); |
---|
| 124 | std::cout << u; // output: hello world |
---|
| 125 | |
---|
| 126 | int result = <functionname>boost::apply_visitor</functionname>( my_visitor(), u ); |
---|
| 127 | std::cout << result; // output: 11 (i.e., length of "hello world") |
---|
| 128 | } |
---|
| 129 | </programlisting> |
---|
| 130 | |
---|
| 131 | </section> |
---|
| 132 | |
---|
| 133 | </section> |
---|
| 134 | |
---|
| 135 | </section> |
---|