mirror of
https://github.com/boostorg/variant.git
synced 2026-02-01 09:02:11 +00:00
247 lines
9.7 KiB
XML
247 lines
9.7 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
|
|
<section id="variant.tutorial.advanced">
|
|
<title>Advanced Topics</title>
|
|
|
|
<using-namespace name="boost"/>
|
|
<using-class name="boost::variant"/>
|
|
|
|
<para>This section discusses several features of the library often required
|
|
for advanced uses of <code>variant</code>. 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.</para>
|
|
|
|
<section id="variant.tutorial.preprocessor">
|
|
<title>Preprocessor macros</title>
|
|
|
|
<para>While the <code>variant</code> 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 <code>variant</code> instantiation, say
|
|
<code>variant<int, std::string></code>, it is less clear how one
|
|
might write a function accepting any given <code>variant</code>.</para>
|
|
|
|
<para>Due to the lack of support for true variadic template parameter lists
|
|
in the C++98 standard, the preprocessor is needed. While the
|
|
<libraryname>Preprocessor</libraryname> library provides a general and
|
|
powerful solution, the need to repeat
|
|
<code><macroname>BOOST_VARIANT_LIMIT_TYPES</macroname></code>
|
|
unnecessarily clutters otherwise simple code. Therefore, for common
|
|
use-cases, this library provides its own macro
|
|
<code><macroname>BOOST_VARIANT_ENUM_PARAMS</macroname></code>.</para>
|
|
|
|
<para>This macro simplifies for the user the process of declaring
|
|
<code>variant</code> types in function templates or explicit partial
|
|
specializations of class templates, as shown in the following:
|
|
|
|
<programlisting>// general cases
|
|
template <typename T> void some_func(const T &);
|
|
template <typename T> class some_class;
|
|
|
|
// function template overload
|
|
template <<emphasis role="bold">BOOST_VARIANT_ENUM_PARAMS(typename T)</emphasis>>
|
|
void some_func(const <classname>boost::variant</classname><<emphasis role="bold">BOOST_VARIANT_ENUM_PARAMS(T)</emphasis>> &);
|
|
|
|
// explicit partial specialization
|
|
template <<emphasis role="bold">BOOST_VARIANT_ENUM_PARAMS(typename T)</emphasis>>
|
|
class some_class< <classname>boost::variant</classname><<emphasis role="bold">BOOST_VARIANT_ENUM_PARAMS(T)</emphasis>> >;</programlisting>
|
|
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section id="variant.tutorial.type-sequence-syntax">
|
|
<title>Alternate declaration syntax:
|
|
<code>variant< <emphasis>type-sequence</emphasis> ></code></title>
|
|
|
|
<para>While convenient for typical uses, the <code>variant</code> 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,
|
|
<code><macroname>BOOST_VARIANT_LIMIT_TYPES</macroname></code>).
|
|
Second, the nature of parameter lists in general makes compile-time
|
|
manipulation of the lists (metaprogramming) excessively difficult.</para>
|
|
|
|
<para>To solve these problems <code>variant</code> offers the following
|
|
alternative declaration syntax:
|
|
<code>variant< <emphasis>type-sequence</emphasis> ></code>. More
|
|
precisely, if an <libraryname>MPL</libraryname>-compatible sequence is
|
|
provided as the first argument to <code>variant</code>, the types
|
|
exposed therein will constitute the set of bounded types for the
|
|
<code>variant</code>. For instance,
|
|
|
|
<programlisting>typedef mpl::vector< std::string > types_initial;
|
|
typedef mpl::push_front< types_initial, int >::type types;
|
|
|
|
<classname>boost::variant</classname>< types > v1;</programlisting>
|
|
|
|
behaves equivalently to
|
|
|
|
<programlisting><classname>boost::variant</classname>< int, std::string > v2;</programlisting>
|
|
|
|
</para>
|
|
|
|
<para><emphasis role="bold">Portability</emphasis>: Unfortunately, due to
|
|
standard conformance issues in several compilers, the alternate
|
|
declaration syntax described above is not universally available. On these
|
|
compilers the library indicates its lack of support for the syntax via the
|
|
definition of the preprocessor symbol
|
|
<code><macroname>BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT</macroname></code>.</para>
|
|
|
|
</section>
|
|
|
|
<section id="variant.tutorial.recursive-variant">
|
|
<title>Recursive types with <code>recursive_variant</code></title>
|
|
|
|
<para>Recursive types facilitate the construction of complex semantics from
|
|
simple snytax. For instance, nearly every programmer is familiar with the
|
|
canonical definition of a linked list implementation, whose simple
|
|
definition allows sequences of unlimited length:
|
|
|
|
<programlisting>template <typename T>
|
|
struct list_node
|
|
{
|
|
T data;
|
|
list_node * next;
|
|
};</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>The nature of <code>variant</code> as a reusable class template
|
|
unfortunately precludes the straightforward construction of recursive
|
|
<code>variant</code> types. Consider for instance a likely initial attempt
|
|
at construction of a tree structure, which uses <code>std::vector</code>
|
|
to provide an unlimited number of branches:
|
|
|
|
<programlisting>typedef <classname>boost::variant</classname><
|
|
int
|
|
, std::vector< /* ??? */ >
|
|
> int_tree_t;</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>Unlike the <code>list_node</code> example above,
|
|
<code>int_tree_t</code> isn't in scope until the end of the declaration.
|
|
The <code>boost::recursive_variant</code> class template solves the
|
|
problem with clean, meaningful syntax:
|
|
|
|
<programlisting>typedef <classname>boost::recursive_variant</classname><
|
|
int
|
|
, std::vector< <classname>boost::recursive_variant_</classname> >
|
|
>::type int_tree_t;</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>Note the trailing <code>::type</code>, accessing the nested type of
|
|
<code>recursive_variant</code>. This less-than-ideal syntax is required
|
|
due to the lack of template typedefs in C++98. Once declared, however,
|
|
use of the resultant <code>variant</code> type is as expected:
|
|
|
|
<programlisting>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);</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>One might represent the resultant content of <code>var</code> as
|
|
<code>( 1 ( 3 5 ) 7 )</code>. The "depth" of this tree could
|
|
of course be greater, and is in fact limited only by available
|
|
memory.</para>
|
|
|
|
<para><emphasis role="bold">Portability</emphasis>: Unfortunately, due to
|
|
standard conformance issues in several compilers,
|
|
<code>recursive_variant</code> is not universally supported. On these
|
|
compilers the library indicates its lack of support for via the definition
|
|
of the preprocessor symbol
|
|
<code><macroname>BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT</macroname></code>.</para>
|
|
|
|
<!-- TODO: mention boost::incomplete workaround -->
|
|
|
|
</section>
|
|
|
|
<section id="variant.tutorial.binary-visitation">
|
|
<title>Binary visitation</title>
|
|
|
|
<para>As the tutorial above demonstrates, visitation is a powerful mechanism
|
|
for manipulating <code>variant</code> content. Binary visitation further
|
|
extends the power and flexibility of visitation by allowing simultaneous
|
|
visitation of the content of two different <code>variant</code>
|
|
objects.</para>
|
|
|
|
<para>Unfortunately, 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:
|
|
|
|
<programlisting>class are_strict_equals
|
|
: public <classname>boost::static_visitor</classname><bool>
|
|
{
|
|
public:
|
|
|
|
template <typename T, typename U>
|
|
bool operator()( const T &, const U & )
|
|
{
|
|
return false; // cannot compare different types
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator()( const T & lhs, const T & rhs )
|
|
{
|
|
return lhs == rhs;
|
|
}
|
|
|
|
};</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>As expected, the visitor is applied to two <code>variant</code>
|
|
arguments by means of <code>apply_visitor</code>:
|
|
|
|
<programlisting><classname>boost::variant</classname>< int, std::string > v1( "hello" );
|
|
|
|
<classname>boost::variant</classname>< double, std::string > v2( "hello" );
|
|
assert( <functionname>boost::apply_visitor</functionname>(are_strict_equals(), v1, v2) );
|
|
|
|
<classname>boost::variant</classname>< int, const char * > v3( "hello" );
|
|
assert( !<functionname>boost::apply_visitor</functionname>(are_strict_equals(), v1, v3) );</programlisting>
|
|
|
|
</para>
|
|
|
|
<para>Finally, we must note that the function object returned from the
|
|
"delayed" form of
|
|
<code><functionname>apply_visitor</functionname></code> also supports
|
|
binary visitation, as the following demonstrates:
|
|
|
|
<programlisting>typedef <classname>boost::variant</classname><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(
|
|
v1.begin(), v1.end(), v2.begin()
|
|
, <functionname>boost::apply_visitor</functionname>( visitor )
|
|
) );</programlisting>
|
|
|
|
</para>
|
|
|
|
</section>
|
|
|
|
</section>
|