|
boost::variantReference |
boost::variant
boost::apply_visitor
boost::static_visitor
boost::get
boost::incomplete
boost::empty
Dependencies and library features defined in
"boost/variant.hpp
":
#define BOOST_VARIANT_LIMIT_TYPES implementation-defined namespace boost { template < typename T1 = boost::empty, typename T2 = implementation-defined, ... typename Tn = implementation-defined > class variant; template <typename T1, typename T2, ... , typename Tn> void swap( variant<T1,T2, ... ,Tn>&, variant<T1,T2, ... ,Tn>&); template < BOOST_TEMPLATED_STREAM_ARGS(E,T), BOOST_TEMPLATED_STREAM_COMMA typename U1, typename U2, ..., typename Un > BOOST_TEMPLATED_STREAM(ostream, E, T)& operator<<(BOOST_TEMPLATED_STREAM(ostream, E, T)& out, const variant<U1,U2, ..., Un>& v); }
Test harnesses provided in "libs/variant/test"
directory.
Given variant
<T1,T2,...,Tn>
,
each type Ti
is a bounded type of the variant
.
The requirements on bounded types are as follows:
const
-qualified. incomplete<T>
wrapper for a solution to containing incomplete types.)Additional requirements on the first type T1:
T1
is a
boost::mpl
sequence,and no other types are specified (i.e: n = 1),
then the instantiated variant will use the types contained in
T1
as its Bounded Types.
T1
must be DefaultConstructible [20.1.4]
if the variant
is expected to be default constructible.
Given variant
<T1,T2,...,Tn>
,
a function object which unambiguously accepts any value of
each of the variant's bounded types, is a
Visitor of of the variant
.
Additional requirements on visitors are as follows:
result_type
,
or - alternatively - derive from
static_visitor
.
operator()
must return a value
that is implicitly-convertible to result_type
.The following class is a visitor of a number of variant
types
(e.g., explicitly: variant<int,std::string>
, or implicitly:
variant<short,std::string>
, etc.):
class my_visitor { typedef int result_type; int operator()(int i) { return i * 2; } int operator()(const std::string& s) { return s.length(); } };
Another example is the following class, which exposes a templated
function call operator, allowing it to operate on values of many types.
Thus, the following class is a visitor of any variant
whose bounded types each support streaming output:
class printer { typedef void result_type; template <typename T> void operator()(const T& t) { std::cout << t << '\n'; } };
#define BOOST_VARIANT_LIMIT_TYPES implementation-defined
Implementation-defined. Equal to the length of the template parameter
list for variant
.
Note: Conforming implementations of variant
must allow at
least ten bounded types. That is, BOOST_VARIANT_LIMIT_TYPES >= 10
must evaluate true.
boost::variant
template < typename T1 = boost::empty, typename T2 = implementation-defined, ... typename Tn = implementation-defined > class variant { public: // structors variant(); variant(const variant &); template <typename OperandType> variant(const OperandType &); ~variant(); public: // modifiers variant & swap(variant &); variant & operator=(const variant &); template <typename OperandType> variant & operator=(const OperandType &); public: // queries int which() const; const std::type_info & type() const; bool empty() const; private: // representation ... };
An instance of variant
contains exactly one instance of one of its
bounded types, which are specified as arguments to variant
's
template parameter list. The length of variant
's template
parameter list is equal to the implementation defined value
BOOST_VARIANT_LIMIT_TYPES
.
Each type specified as a bounded type must satisfy the BoundedType
requirements. Note that variant
itself satisfies
BoundedType requirements with default construction.
All members of variant
satisfy the strong guarantee of
exception-safety.
Structors
variant();Default constructor. Initializes
*this
with the default value of the first bounded type (i.e,T1
). May fail with any exceptions arising from the default constructor ofT1
.
variant(const variant& other);Copy constructor. Copies the content of
other
into*this
. May fail with any exceptions arising from the copy constructor ofother
's contained type.
template <typename OperandType> variant(const OperandType & operand);Templated constructor. Initializes
*this
according to the following logic:
- If
OperandType
is not avariant
:
- If
OperandType
is one of the bounded types of thevariant
, initialize*this
with a copy ofoperand
.- Otherwise, use overload resolution rules to find the best conversion for
OperandType
, and initialize*this
with a copy of the convertedoperand
. (However, if the conversion is ambiguous, or if none exists, a compiler error is generated.)- Otherwise (i.e:
OperandType
is avariant
):
- If
OperandType
does not appear on*this
's set of types, then*this
is initialized withoperand
's held value (as described in item 1, above).- Otherwise,
operand
is assigned, as-is, into*this
. Hence, the held value of*this
is, by itself, a variant.May fail with any exceptions arising from the copy constructor of
OperandType
.
~variant();Non-throwing destructor that releases all resources used in management of
*this
, including the currently contained value.Modifiers
void swap(variant& other);Exchanges contents of
*this
andother
. May fail with any exceptions arising from the copy constructors of the contained types of*this
orother
, or from the swap primitive of the held values, ifthis->type() == other.type()
.
variant& operator=(const variant& rhs);Copy assignment. Assigns
rhs
's contained value into*this
. The old value contained by*this
is properly destroyed.Note: this operator follows the same logic as the copy constructor.
template<class OperandType> variant& operator=(const OperandType &);Templated assignment. Assigns
rhs
into*this
. The old value held by*this
is properly destroyed.Note: This operator follows the same logic as the templated constructor.
Queries
const std::type_info & type() const;Non-throwing query that returns the
typeid()
of the contained valuebool empty() const;Non-throwing query that returns
true
if, and only if, the held value is of typeboost::empty
.
Consequently, ifboost::empty
is not one of the BoundedTypes, thenempty()
will always yieldfalse
.int which() const;Non-throwing query that returns the zero-based index of the bounded type of the contained value.
apply_visitor
// Binary form template<typename VisitorType, typename VariantType> typename VisitorType::result_type apply_visitor(VisitorType& visitor, VariantType& var_inst); // Unary form template<class VisitorType> boost::apply_visitor_t<VisitorType> apply_visitor(VisitorType& visitor); template <typename VisitorType> class apply_visitor_t { public: typedef typename VisitorType::result_type result_type; template <typename VariantType> result_type operator()(VariantType& var_inst); ... };
boost::apply_visitor(visitor, var_inst)
passes the variant object,
var_inst
, to the given visitor (visitor
). This is
equivalent to calling visitor
's function-call operator, with var_inst
's
currently held value.
VisitorType
must be a visitor of VariantType
.
See Functor-based visitation
for an in-depth description of visitors.
The unary form of apply_visitor()
tranforms the given visitor into
a unary function object which accepts a variant object, thus, the following two
lines are equivalent:
boost::apply_visitor(visitor, var_inst); // Binary form boost::apply_visitor(visitor)(var_inst); // Unary form
Consequently, the unary apply_visitor()
function, is highly useful
when std::for_each
(or a similar STL algorithm) needs to be
applied on a sequence of variant
objects, as illustrated in the
Polymorphism: Inheritance Vs. Variants sample.
static_visitor
template<typename R = void> struct static_visitor { typedef R result_type; };
static_visitor
defines the nested type result_type
,
which is required from each visitor class.
get
class bad_get : public std::exception { public: virtual const char* what() const throw(); }; template<typename ToType,typename T1, typename T2, ...> ToType& get(boost::variant<T1,T2,...>& v); template<typename ToType,typename T1, typename T2, ...> const ToType& get(const boost::variant<T1,T2,...>& v); template<typename ToType,typename T1, typename T2, ...> ToType* get(boost::variant<T1,T2,...>* v); template<typename ToType,typename T1, typename T2, ...> const ToType* get(const boost::variant<T1,T2,...>* v);Returns a reference/pointer to a held value:
ToType
. Otherwise, returns NULL
.ToType
. Otherwise, throws a bad_get
exception.incomplete
incomplete<T>
is a class template, which allows a variant
type to be instantiated with incomplete types.
By specifying incomplete<T>
as one of the actual template
parameters, the instantiated variant will be able to handle values of type T
,
although T
is incomplete at the instantiation point.
incomplete<>
is typically used for solving circular
dependencies, but, more importantly, it also enables the creation of recursive,
variant-based, constructs.
Note that using incomplete<T>
instructs the concrete
variant
type to employ heap allocation scheme
for storing values of type T
("Reference Semantics"). This
is opposite to the to the standard case, where values of complete types
are stored within the variant
object itself ("Value
Semantics").
The snip below demonstrates the usage of incomplete<>
. A
complete sample program is available here.
using boost::variant; using boost::incomplete; struct non_leaf_node; // Forward declaration // Define a tree_node variant with these two types: // (1) int, (2) non_leaf node typedef variant < int, incomplete<non_leaf_node> // non_leaf_node is incomplete at // this point so it must be wrapperd // by incomplete<> > tree_node; struct non_leaf_node { non_leaf_node(const non_leaf_node& other) : left_(other.left_), right_(other.right_), num_(other.num_) { } int num_; tree_node left_; tree_node right_; };
empty
struct empty { }; bool operator==(const empty&, const empty&); // Always true bool operator<(const empty&, const empty&); // Always false BOOST_TEMPLATED_STREAM_TEMPLATE(E,T) BOOST_TEMPLATED_STREAM(ostream, E,T)& operator<<(BOOST_TEMPLATED_STREAM(ostream, E,T)&, const empty& ); // NOP
A variant
object holding a value of
type boost::empty
is considered to be empty.
This convention is acknowledged by varinat::empty()
: Its
return value is true
, if and only if the held value is of type
boost::empty
.
Public interface
operator==(const empty&, const empty&)
always returns true
, while
operator<(const empty&, const empty&)
always returns
false
.operator<<
has a "Do-nothing" behavior when
invoked with a boost::empty
value.
variant
object that does not have boost::empty
as one of its BoundedTypes, can never be in an empty
state. At any given point it holds a valid value.
boost::empty
value.
boost::empty
has no state. Thus, when two instances of
boost::empty
are tested for equality, the result is always
true
.The following snip demonstrates an optional string value, using a variant
whose bounded types are boost::empty
and
std::string
:
typedef boost::variant<boost::empty,std::string> string_or_nothing; void print(const string_or_nothing& a) { if(a.empty()) cout << "No string is specified" << endl; else cout << boost::get<const std::string>(a) << endl; } int main() { string_or_nothing s; print(s); // Output: "No string is specified" s = "Ford Prefect"; print(s); // Output: "Ford Prefect" return 0; }
Revised 28 July 2003
© Copyright Eric Friedman and Itay Maman 2002-2003. All rights reserved.
Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Eric Friedman and Itay Maman make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.