|  | Home | Libraries | People | FAQ | More | 
A discriminated union container on some set of types is defined by
  instantiating the boost::variant class
  template with the desired types. These types are called
  bounded types and are subject to the
  requirements of the
  BoundedType
  concept. Any number of bounded types may be specified, up to some
  implementation-defined limit (see 
  BOOST_VARIANT_LIMIT_TYPES).
For example, the following declares a discriminated union container on
  int and std::string:
boost::variant< int, std::string > v;
By default, a variant default-constructs its first
  bounded type, so v initially contains int(0). If
  this is not desired, or if the first bounded type is not
  default-constructible, a variant can be constructed
  directly from any value convertible to one of its bounded types. Similarly,
  a variant can be assigned any value convertible to one of its
  bounded types, as demonstrated in the following:
v = "hello";
Now v contains a std::string equal to
  "hello". We can demonstrate this by
  streaming v to standard
  output:
std::cout << v << std::endl;
Usually though, we would like to do more with the content of a
  variant than streaming. Thus, we need some way to access the
  contained value. There are two ways to accomplish this:
  apply_visitor, which is safest
  and very powerful, and
  get<T>, which is
  sometimes more convenient to use.
For instance, suppose we wanted to concatenate to the string contained
  in v. With value retrieval
  by get, this may be accomplished
  quite simply, as seen in the following:
std::string& str = boost::get<std::string>(v);
str += " world! ";
As desired, the std::string contained by v now
  is equal to "hello world! ". Again, we can demonstrate this by
  streaming v to standard output:
std::cout << v << std::endl;
While use of get is perfectly acceptable in this trivial
  example, get generally suffers from several significant
  shortcomings. For instance, if we were to write a function accepting a
  variant<int, std::string>, we would not know whether
  the passed variant contained an int or a
  std::string. If we insisted upon continued use of
  get, we would need to query the variant for its
  contained type. The following function, which "doubles" the
  content of the given variant, demonstrates this approach:
void times_two( boost::variant< int, std::string > & operand )
{
    if ( int* pi = boost::get<int>( &operand ) )
        *pi *= 2;
    else if ( std::string* pstr = boost::get<std::string>( &operand ) )
        *pstr += *pstr;
}
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
  times_two to operate on a variant with additional
  bounded types. Specifically, let's add
  std::complex<double> to the set. Clearly, we would need
  to at least change the function declaration:
void times_two( boost::variant< int, std::string, std::complex<double> > & operand )
{
    // as above...?
}
Of course, additional changes are required, for currently if the passed
  variant in fact contained a std::complex value,
  times_two 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.
Thus, real-world use of variant typically demands an access
  mechanism more robust than get. For this reason,
  variant supports compile-time checked
  visitation via
  apply_visitor. Visitation requires
  that the programmer explicitly handle (or ignore) each bounded type. Failure
  to do so results in a compile-time error.
Visitation of a variant requires a visitor object. The
  following demonstrates one such implementation of a visitor implementating
  behavior identical to times_two:
class times_two_visitor
    : public boost::static_visitor<>
{
public:
    void operator()(int & i) const
    {
        i *= 2;
    }
    void operator()(std::string & str) const
    {
        str += str;
    }
};
With the implementation of the above visitor, we can then apply it to
  v, as seen in the following:
boost::apply_visitor( times_two_visitor(), v );
As expected, the content of v is now a
  std::string equal to "hello world! hello world! ".
  (We'll skip the verification this time.)
In addition to enhanced robustness, visitation provides another
  important advantage over get: the ability to write generic
  visitors. For instance, the following visitor will "double" the
  content of any variant (provided its
  bounded types each support operator+=):
class times_two_generic
    : public boost::static_visitor<>
{
public:
    template <typename T>
    void operator()( T & operand ) const
    {
        operand += operand;
    }
};
Again, apply_visitor sets the wheels in motion:
boost::apply_visitor( times_two_generic(), v );
While the initial setup costs of visitation may exceed that required for
  get, the benefits quickly become significant. Before concluding
  this section, we should explore one last benefit of visitation with
  apply_visitor:
  delayed visitation. Namely, a special form
  of apply_visitor is available that does not immediately apply
  the given visitor to any variant but rather returns a function
  object that operates on any variant given to it. This behavior
  is particularly useful when operating on sequences of variant
  type, as the following demonstrates:
std::vector<boost::variant<int, std::string> > vec; vec.push_back( 21 ); vec.push_back( "hello " ); times_two_generic visitor; std::for_each( vec.begin(), vec.end() ,boost::apply_visitor(visitor) );
This section discusses several features of the library often required
  for advanced uses of variant. 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.
While the variant 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 variant instantiation, say
    variant<int, std::string>, it is less clear how one
    might write a function accepting any given variant.
Due to the lack of support for true variadic template parameter lists
    in the C++98 standard, the preprocessor is needed. While the
    Preprocessor library provides a general and
    powerful solution, the need to repeat
    BOOST_VARIANT_LIMIT_TYPES
    unnecessarily clutters otherwise simple code. Therefore, for common
    use-cases, this library provides its own macro
    BOOST_VARIANT_ENUM_PARAMS.
This macro simplifies for the user the process of declaring 
    variant types in function templates or explicit partial
    specializations of class templates, as shown in the following:
// general cases template <typename T> void some_func(const T &); template <typename T> class some_class; // function template overload template <BOOST_VARIANT_ENUM_PARAMS(typename T)> void some_func(constboost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &); // explicit partial specialization template <BOOST_VARIANT_ENUM_PARAMS(typename T)> class some_class<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >;
While convenient for typical uses, the variant 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,
    BOOST_VARIANT_LIMIT_TYPES).
    Second, the nature of parameter lists in general makes compile-time
    manipulation of the lists excessively difficult.
To solve these problems,
    make_variant_over< Sequence >
    exposes a variant whose bounded types are the elements of
    Sequence (where Sequence is any type fulfilling
    the requirements of MPL's
    Sequence concept). For instance,
typedefmpl::vector< std::string > types_initial; typedefmpl::push_front< types_initial, int >::type types;boost::make_variant_over< types >::type v1;
behaves equivalently to
boost::variant< int, std::string > v2;
Portability: Unfortunately, due to
    standard conformance issues in several compilers,
    make_variant_over is not universally available. On these
    compilers the library indicates its lack of support for the syntax via the
    definition of the preprocessor symbol
    BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT.
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:
template <typename T>
struct list_node
{
    T data;
    list_node * next;
};
The nature of variant as a generic class template
    unfortunately precludes the straightforward construction of recursive
    variant types. Consider the following attempt to construct
    a structure for simple mathematical expressions:
    
struct add;
struct sub;
template <typename OpTag> struct binary_op;
typedef boost::variant<
      int
    , binary_op<add>
    , binary_op<sub>
    > expression;
template <typename OpTag>
struct binary_op
{
    expression left;  // variant instantiated here...
    expression right;
    binary_op( const expression & lhs, const expression & rhs )
        : left(lhs), right(rhs)
    {
    }
}; // ...but binary_op not complete until here!
While well-intentioned, the above approach will not compile because
    binary_op is still incomplete when the variant
    type expression 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,"
    expression would need to be of infinite size, which is
    clearly impossible.
To overcome these difficulties, variant includes special
    support for the
    boost::recursive_wrapper class
    template, which breaks the circular dependency at the heart of these
    problems. Further,
    boost::make_recursive_variant provides
    a more convenient syntax for declaring recursive variant
    types. Tutorials for use of these facilities is described in
    the section called “Recursive types with recursive_wrapper” and
    the section called “Recursive types with make_recursive_variant”.
The following example demonstrates how recursive_wrapper
    could be used to solve the problem presented in
    the section called “Recursive variant types”:
    
typedefboost::variant< int ,boost::recursive_wrapper< binary_op<add> > ,boost::recursive_wrapper< binary_op<sub> > > expression;
Because variant provides special support for
    recursive_wrapper, clients may treat the resultant
    variant as though the wrapper were not present. This is seen
    in the implementation of the following visitor, which calculates the value
    of an expression without any reference to
    recursive_wrapper:
    
class calculator : publicboost::static_visitor<int>{ public: int operator()(int value) const { return value; } int operator()(const binary_op<add> & binary) const { returnboost::apply_visitor( calculator(), binary.left ) +boost::apply_visitor( calculator(), binary.right ); } int operator()(const binary_op<sub> & binary) const { returnboost::apply_visitor( calculator(), binary.left ) -boost::apply_visitor( calculator(), binary.right ); } };
Finally, we can demonstrate expression in action:
  
    
void f()
{
    // result = ((7-3)+8) = 12
    expression result(
        binary_op<add>(
            binary_op<sub>(7,3)
          , 8
          )
      );
    assert( boost::apply_visitor(calculator(),result) == 12 );
}
Performance: boost::recursive_wrapper
    has no empty state, which makes its move constructor not very optimal. Consider using std::unique_ptr 
    or some other safe pointer for better performance on C++11 compatible compilers.
For some applications of recursive variant types, a user
    may be able to sacrifice the full flexibility of using
    recursive_wrapper with variant for the following
    convenient syntax:
typedef boost::make_recursive_variant<
      int
    , std::vector< boost::recursive_variant_ >
    >::type int_tree_t;
Use of the resultant variant type is as expected:
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);
To be clear, one might represent the resultant content of
    var as ( 1 ( 3 5 ) 7 ).
Finally, note that a type sequence can be used to specify the bounded
    types of a recursive variant via the use of
    boost::make_recursive_variant_over,
    whose semantics are the same as make_variant_over (which is
    described in the section called “Using a type sequence to specify bounded types”).
Portability: Unfortunately, due to
    standard conformance issues in several compilers,
    make_recursive_variant is not universally supported. On these
    compilers the library indicates its lack of support via the definition
    of the preprocessor symbol
    BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT.
    Thus, unless working with highly-conformant compilers, maximum portability
    will be achieved by instead using recursive_wrapper, as
    described in
    the section called “Recursive types with recursive_wrapper”.
As the tutorial above demonstrates, visitation is a powerful mechanism
    for manipulating variant content. Binary visitation further
    extends the power and flexibility of visitation by allowing simultaneous
    visitation of the content of two different variant
    objects.
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:
class are_strict_equals
    : public boost::static_visitor<bool>
{
public:
    template <typename T, typename U>
    bool operator()( const T &, const U & ) const
    {
        return false; // cannot compare different types
    }
    template <typename T>
    bool operator()( const T & lhs, const T & rhs ) const
    {
        return lhs == rhs;
    }
};
As expected, the visitor is applied to two variant
    arguments by means of apply_visitor:
boost::variant< int, std::string > v1( "hello" );boost::variant< double, std::string > v2( "hello" ); assert(boost::apply_visitor(are_strict_equals(), v1, v2) );boost::variant< int, const char * > v3( "hello" ); assert( !boost::apply_visitor(are_strict_equals(), v1, v3) );
Finally, we must note that the function object returned from the
    "delayed" form of
    apply_visitor also supports
    binary visitation, as the following demonstrates:
typedefboost::variant<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( seq1.begin(), seq1.end(), seq2.begin() ,boost::apply_visitor( visitor ) ) );
Multi visitation extends the power and flexibility of visitation by allowing simultaneous
    visitation of the content of three and more different variant
    objects. Note that header for multi visitors shall be included separately.
Notably this feature requires that multi visitors are incompatible
    with the visitor objects discussed in the tutorial above, as they must
    operate on same amout of arguments that was passed to apply_visitor. 
    The following demonstrates the implementation of a multi visitor for three parameters:
#include <boost/variant/multivisitors.hpp> typedefboost::variant<int, double, bool> bool_like_t; typedefboost::variant<int, double> arithmetics_t; struct if_visitor: publicboost::static_visitor<arithmetics_t> { template <class T1, class T2> arithmetics_t operator()(bool b, T1 v1, T2 v2) const { if (b) { return v1; } else { return v2; } } };
As expected, the visitor is applied to three variant
    arguments by means of apply_visitor:
bool_like_t v0(true), v1(1), v2(2.0);
assert(
    boost::apply_visitor(if_visitor(), v0, v1, v2)
    ==
    arithmetics_t(1)
);
Finally, we must note that multi visitation does not support 
    "delayed" form of
    apply_visitor if
    BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES is defined.