IntroductionAbstractThe variant 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 std::vector may be thought of as
"multi-value, single type,"
variant is "multi-type,
single value."Notable features of boost::variant
include:Full value semantics, including adherence to standard
overload resolution rules for conversion operations.Compile-time type-safe value visitation via
boost::apply_visitor.Run-time checked explicit value retrieval via
boost::get.Support for recursive variant types via both
boost::make_recursive_variant and
boost::recursive_wrapper.Efficient implementation -- stack-based when possible (see
for more details).MotivationProblemMany 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 union
keyword:union { int i; double d; } u;
u.d = 3.14;
u.i = 3; // overwrites u.d (OK: u.d is a POD type)C++'s union 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:union {
int i;
std::string s; // illegal: std::string is not a POD type!
} u;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
[Hen01]
or, more dangerously, a void*). Objects of
concrete type may be then retrieved by way of a polymorphic downcast
construct (e.g., dynamic_cast,
boost::any_cast, etc.).However, solutions of this sort are highly error-prone, due
to the following:Downcast errors cannot be detected at
compile-time. Thus, incorrect usage of downcast
constructs will lead to bugs detectable only at run-time.Addition of new concrete types may be
ignored. 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.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.Solution: A Motivating ExampleThe boost::variant class template
addresses these issues in a safe, straightforward, and efficient manner. The
following example demonstrates how the class can be used:#include "boost/variant.hpp"
#include <iostream>
class my_visitor : public boost::static_visitor<int>
{
public:
int operator()(int i) const
{
return i;
}
int operator()(const std::string & str) const
{
return str.length();
}
};
int main()
{
boost::variant< int, std::string > u("hello world");
std::cout << u; // output: hello world
int result = boost::apply_visitor( my_visitor(), u );
std::cout << result; // output: 11 (i.e., length of "hello world")
}