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