491 lines
19 KiB
Plaintext
491 lines
19 KiB
Plaintext
[/==============================================================================
|
|
Copyright (C) 2001-2011 Joel de Guzman
|
|
Copyright (C) 2006 Dan Marsden
|
|
|
|
Use, modification and distribution is subject to the Boost Software
|
|
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt)
|
|
===============================================================================/]
|
|
[section Extension]
|
|
|
|
[section:ext_full The Full Extension Mechanism]
|
|
|
|
The Fusion library is designed to be extensible, new sequences types can easily
|
|
be added. In fact, the library support for `std::pair`, `boost::array` and __mpl__
|
|
sequences is entirely provided using the extension mechanism.
|
|
|
|
The process for adding a new sequence type to Fusion is:
|
|
|
|
# Enable the __tag_dispatching__ mechanism used by Fusion for your sequence type
|
|
# Design an iterator type for the sequence
|
|
# Provide specialized behaviour for the intrinsic operations of the new Fusion sequence
|
|
|
|
[heading Our example]
|
|
|
|
In order to illustrate enabling a new sequence type for use with Fusion, we
|
|
are going to use the type:
|
|
|
|
namespace example
|
|
{
|
|
struct example_struct
|
|
{
|
|
std::string name;
|
|
int age;
|
|
example_struct(
|
|
const std::string& n,
|
|
int a)
|
|
: name(n), age(a)
|
|
{}
|
|
};
|
|
}
|
|
|
|
We are going to pretend that this type has been provided by a 3rd party
|
|
library, and therefore cannot be modified. We shall work through all the
|
|
necessary steps to enable `example_struct` to serve as an __associative_sequence__
|
|
as described in the __quick_start__ guide.
|
|
|
|
[heading Enabling Tag Dispatching]
|
|
|
|
The Fusion extensibility mechanism uses __tag_dispatching__ to call the
|
|
correct code for a given sequence type. In order to exploit the tag
|
|
dispatching mechanism we must first declare a new tag type for the
|
|
mechanism to use. For example:
|
|
|
|
namespace example {
|
|
struct example_sequence_tag; // Only definition needed
|
|
}
|
|
|
|
Next we need to enable the `traits::tag_of` metafunction to return our newly chosen
|
|
tag type for operations involving our sequence. This is done by specializing
|
|
`traits::tag_of` for our sequence type.
|
|
|
|
#include <boost/fusion/support/tag_of_fwd.hpp>
|
|
#include <boost/fusion/include/tag_of_fwd.hpp>
|
|
|
|
namespace boost { namespace fusion { namespace traits {
|
|
template<>
|
|
struct tag_of<example_struct>
|
|
{
|
|
typedef example::example_sequence_tag type;
|
|
};
|
|
}}}
|
|
|
|
`traits::tag_of` also has a second template argument,
|
|
that can be used in conjunction with `boost::enable_if` to provide tag
|
|
support for groups of related types. This feature is not necessary
|
|
for our sequence, but for an example see the code in:
|
|
|
|
#include <boost/fusion/adapted/array/tag_of.hpp>
|
|
#include <boost/fusion/include/tag_of.hpp>
|
|
|
|
[heading Designing a suitable iterator]
|
|
|
|
We need an iterator to describe positions, and provide access to
|
|
the data within our sequence. As it is straightforward to do,
|
|
we are going to provide a random access iterator in our example.
|
|
|
|
We will use a simple design, in which the 2 members of
|
|
`example_struct` are given numbered indices, 0 for `name` and
|
|
1 for `age` respectively.
|
|
|
|
template<typename Struct, int Pos>
|
|
struct example_struct_iterator
|
|
: boost::fusion::iterator_base<example_struct_iterator<Struct, Pos> >
|
|
{
|
|
BOOST_STATIC_ASSERT(Pos >=0 && Pos < 3);
|
|
typedef Struct struct_type;
|
|
typedef boost::mpl::int_<Pos> index;
|
|
typedef boost::fusion::random_access_traversal_tag category;
|
|
|
|
example_struct_iterator(Struct& str)
|
|
: struct_(str) {}
|
|
|
|
Struct& struct_;
|
|
};
|
|
|
|
A quick summary of the details of our iterator:
|
|
|
|
# The iterator is parameterized by the type it is iterating over, and the index of the current element.
|
|
# The typedefs `struct_type` and `index` provide convenient access to information we will need later in
|
|
the implementation.
|
|
# The typedef `category` allows the `traits::__category_of__` metafunction to establish
|
|
the traversal category of the iterator.
|
|
# The constructor stores a reference to the `example_struct` being iterated over.
|
|
|
|
We also need to enable __tag_dispatching__ for our iterator type, with another specialization of
|
|
`traits::tag_of`.
|
|
|
|
In isolation, the iterator implementation is pretty dry. Things should become clearer as we
|
|
add features to our implementation.
|
|
|
|
[heading A first couple of instructive features]
|
|
|
|
To start with, we will get the __result_of_value_of__ metafunction working. To
|
|
do this, we provide a specialization of the `boost::fusion::extension::value_of_impl` template for
|
|
our iterator's tag type.
|
|
|
|
template<>
|
|
struct value_of_impl<example::example_struct_iterator_tag>
|
|
{
|
|
template<typename Iterator>
|
|
struct apply;
|
|
|
|
template<typename Struct>
|
|
struct apply<example::example_struct_iterator<Struct, 0> >
|
|
{
|
|
typedef std::string type;
|
|
};
|
|
|
|
template<typename Struct>
|
|
struct apply<example::example_struct_iterator<Struct, 1> >
|
|
{
|
|
typedef int type;
|
|
};
|
|
};
|
|
|
|
The implementation itself is pretty simple, it just uses 2 partial specializations to
|
|
provide the type of the 2 different members of `example_struct`, based on the index of the iterator.
|
|
|
|
To understand how `value_of_impl` is used by the library we will look at the implementation of __result_of_value_of__:
|
|
|
|
template <typename Iterator>
|
|
struct value_of
|
|
: extension::value_of_impl<typename detail::tag_of<Iterator>::type>::
|
|
template apply<Iterator>
|
|
{};
|
|
|
|
So __result_of_value_of__ uses __tag_dispatching__ to select an __mpl_metafunction_class__
|
|
to provide its functionality. You will notice this pattern throughout the
|
|
implementation of Fusion.
|
|
|
|
Ok, lets enable dereferencing of our iterator. In this case we must provide a suitable
|
|
specialization of `deref_impl`.
|
|
|
|
template<>
|
|
struct deref_impl<example::example_struct_iterator_tag>
|
|
{
|
|
template<typename Iterator>
|
|
struct apply;
|
|
|
|
template<typename Struct>
|
|
struct apply<example::example_struct_iterator<Struct, 0> >
|
|
{
|
|
typedef typename mpl::if_<
|
|
is_const<Struct>, std::string const&, std::string&>::type type;
|
|
|
|
static type
|
|
call(example::example_struct_iterator<Struct, 0> const& it)
|
|
{
|
|
return it.struct_.name;
|
|
}
|
|
};
|
|
|
|
template<typename Struct>
|
|
struct apply<example::example_struct_iterator<Struct, 1> >
|
|
{
|
|
typedef typename mpl::if_<
|
|
is_const<Struct>, int const&, int&>::type type;
|
|
|
|
static type
|
|
call(example::example_struct_iterator<Struct, 1> const& it)
|
|
{
|
|
return it.struct_.age;
|
|
}
|
|
};
|
|
};
|
|
}
|
|
|
|
The use of `deref_impl` is very similar to that of `value_of_impl`, but it also
|
|
provides some runtime functionality this time via the `call` static member function.
|
|
To see how `deref_impl` is used, lets have a look at the implementation of __deref__:
|
|
|
|
namespace result_of
|
|
{
|
|
template <typename Iterator>
|
|
struct __deref__
|
|
: extension::deref_impl<typename detail::tag_of<Iterator>::type>::
|
|
template apply<Iterator>
|
|
{};
|
|
}
|
|
|
|
template <typename Iterator>
|
|
typename result_of::deref<Iterator>::type
|
|
__deref__(Iterator const& i)
|
|
{
|
|
typedef result_of::deref<Iterator> deref_meta;
|
|
return deref_meta::call(i);
|
|
}
|
|
|
|
So again __result_of_deref__ uses __tag_dispatching__ in exactly the
|
|
same way as the __result_of_value_of__ implementation. The runtime functionality used
|
|
by __deref__ is provided by the `call` static function of the selected
|
|
__mpl_metafunction_class__.
|
|
|
|
The actual implementation of `deref_impl` is slightly more complex than that of `value_of_impl`.
|
|
We also need to implement the `call` function, which returns a reference
|
|
to the appropriate member of the underlying sequence. We also require a little
|
|
bit of metaprogramming to return `const` references if the underlying sequence
|
|
is const.
|
|
|
|
[note Although there is a fair amount of left to do to produce a fully fledged
|
|
Fusion sequence, __result_of_value_of__ and __deref__ illustrate all the significant concepts
|
|
required. The remainder of the process is very repetitive, simply requiring
|
|
implementation of a suitable `xxxx_impl` for each feature `xxxx`.
|
|
]
|
|
|
|
[heading Implementing the remaining iterator functionality]
|
|
|
|
Ok, now we have seen the way __result_of_value_of__ and __deref__ work, everything else will work
|
|
in pretty much the same way. Lets start with forward iteration,
|
|
by providing a `next_impl`:
|
|
|
|
template<>
|
|
struct next_impl<example::example_struct_iterator_tag>
|
|
{
|
|
template<typename Iterator>
|
|
struct apply
|
|
{
|
|
typedef typename Iterator::struct_type struct_type;
|
|
typedef typename Iterator::index index;
|
|
typedef example::example_struct_iterator<struct_type, index::value + 1> type;
|
|
|
|
static type
|
|
call(Iterator const& i)
|
|
{
|
|
return type(i.struct_);
|
|
}
|
|
};
|
|
};
|
|
|
|
This should be very familiar from our `deref_impl` implementation, we will be
|
|
using this approach again and again now. Our design is simply to increment
|
|
the `index` counter to move on to the next element. The various other iterator
|
|
manipulations we need to perform will all just involve simple calculations
|
|
with the `index` variables.
|
|
|
|
We also need to provide a suitable `equal_to_impl` so that iterators can be
|
|
correctly compared. A __bidirectional_iterator__ will also need an implementation of `prior_impl`. For a
|
|
__random_access_iterator__ `distance_impl` and `advance_impl` also need to be provided
|
|
in order to satisfy the necessary complexity guarantees. As our iterator is
|
|
a __random_access_iterator__ we will have to implement all of these functions.
|
|
|
|
Full implementations of `prior_impl`, `advance_impl`, `distance_impl` and `equal_to_impl` are
|
|
provided in the example code.
|
|
|
|
[heading Implementing the intrinsic functions of the sequence]
|
|
|
|
In order that Fusion can correctly identify our sequence as a Fusion sequence, we
|
|
need to enable `is_sequence` for our sequence type. As usual we just create
|
|
an `impl` type specialized for our sequence tag:
|
|
|
|
template<>
|
|
struct is_sequence_impl<example::example_sequence_tag>
|
|
{
|
|
template<typename T>
|
|
struct apply : mpl::true_ {};
|
|
};
|
|
|
|
We've some similar formalities to complete, providing `category_of_impl` so Fusion
|
|
can correctly identify our sequence type, and `is_view_impl` so Fusion can correctly
|
|
identify our sequence as not being a __view__ type. Implementations are
|
|
provide in the example code.
|
|
|
|
Now we've completed some formalities, on to more interesting features. Lets get
|
|
__begin__ working so that we can get an iterator to start accessing the data in
|
|
our sequence.
|
|
|
|
template<>
|
|
struct begin_impl<example::example_sequence_tag>
|
|
{
|
|
template<typename Sequence>
|
|
struct apply
|
|
{
|
|
typedef example::example_struct_iterator<Sequence, 0> type;
|
|
|
|
static type
|
|
call(Sequence& seq)
|
|
{
|
|
return type(seq);
|
|
}
|
|
};
|
|
};
|
|
|
|
The implementation uses the same ideas we have applied throughout, in this case
|
|
we are just creating one of the iterators we developed earlier, pointing to the
|
|
first element in the sequence. The implementation of __end__ is very similar, and
|
|
is provided in the example code.
|
|
|
|
For our __random_access_sequence__ we will also need to implement `size_impl`,
|
|
`value_at_impl` and `at_impl`.
|
|
|
|
[heading Enabling our type as an associative sequence]
|
|
|
|
In order for `example_struct` to serve as an associative forward sequence,
|
|
we need to adapt the traversal category of our sequence and our iterator
|
|
accordingly and enable 3 intrinsic sequence lookup features, __at_key__,
|
|
__result_of_value_at_key__ and __has_key__. We also need to enable 3 iterator lookup
|
|
features, __result_of_key_of__, __result_of_value_of_data__ and __deref_data__.
|
|
|
|
To implement `at_key_impl` we need to associate the `fields::name` and `fields::age`
|
|
types described in the __quick_start__ guide with the appropriate members of `example_struct`.
|
|
Our implementation is as follows:
|
|
|
|
template<>
|
|
struct at_key_impl<example::example_sequence_tag>
|
|
{
|
|
template<typename Sequence, typename Key>
|
|
struct apply;
|
|
|
|
template<typename Sequence>
|
|
struct apply<Sequence, fields::name>
|
|
{
|
|
typedef typename mpl::if_<
|
|
is_const<Sequence>,
|
|
std::string const&,
|
|
std::string&>::type type;
|
|
|
|
static type
|
|
call(Sequence& seq)
|
|
{
|
|
return seq.name;
|
|
};
|
|
};
|
|
|
|
template<typename Sequence>
|
|
struct apply<Sequence, fields::age>
|
|
{
|
|
typedef typename mpl::if_<
|
|
is_const<Sequence>,
|
|
int const&,
|
|
int&>::type type;
|
|
|
|
static type
|
|
call(Sequence& seq)
|
|
{
|
|
return seq.age;
|
|
};
|
|
};
|
|
};
|
|
|
|
Its all very similar to the implementations we've seen previously,
|
|
such as `deref_impl` and `value_of_impl`. Instead of identifying
|
|
the members by index or position, we are now selecting them using
|
|
the types `fields::name` and `fields::age`. The implementations of
|
|
the other functions are equally straightforward, and are provided in
|
|
the example code.
|
|
|
|
[heading Summary]
|
|
|
|
We've now worked through the entire process for adding a new random
|
|
access sequence and we've also enabled our type to serve as an associative
|
|
sequence. The implementation was slightly long-winded, but followed
|
|
a simple repeating pattern.
|
|
|
|
The support for `std::pair`, __mpl__ sequences, and `boost::array` all
|
|
use the same approach, and provide additional examples of the approach
|
|
for a variety of types.
|
|
|
|
[endsect]
|
|
|
|
[section Sequence Facade]
|
|
|
|
[heading Description]
|
|
The __sequence_facade__ template provides an intrusive mechanism for
|
|
producing a conforming Fusion sequence.
|
|
|
|
[heading Synopsis]
|
|
template<typename Derived, typename TravesalTag, typename IsView = mpl::false_>
|
|
struct sequence_facade;
|
|
|
|
[heading Usage]
|
|
The user of __sequence_facade__ derives his sequence type from a specialization of __sequence_facade__ and passes the derived sequence type as the first template parameter. The second template parameter should be the traversal category of the sequence being implemented. The 3rd parameter should be set to `mpl::true_` if the sequence is a view.
|
|
|
|
The user must implement the key expressions required by their sequence type.
|
|
|
|
[table Parameters
|
|
[[Name][Description]]
|
|
[[`sequence`, `Seq`][A type derived from __sequence_facade__]]
|
|
[[`N`][An __mpl_integral_constant__]]
|
|
]
|
|
|
|
[table Key Expressions
|
|
[[Expression][Result]]
|
|
[[`sequence::template begin<Seq>::type`][The type of an iterator to the beginning of a sequence of type `Seq`]]
|
|
[[`sequence::template begin<Seq>::call(seq)`][An iterator to the beginning of sequence `seq`]]
|
|
[[`sequence::template end<Seq>::type`][The type of an iterator to the end of a sequence of type `Seq`]]
|
|
[[`sequence::template end<Seq>::call(seq)`][An iterator to the end of sequence `seq`]]
|
|
[[`sequence::template size<Seq>::type`][The size of a sequence of type `Seq` as an __mpl_integral_constant__]]
|
|
[[`sequence::template size<Seq>::call(seq)`][The size of sequence `seq`]]
|
|
[[`sequence::template empty<Seq>::type`][Returns `mpl::true_` if `Seq` has zero elements, `mpl::false_` otherwise.]]
|
|
[[`sequence::template empty<Seq>::call`][Returns a type convertible to `bool` that evaluates to true if the sequence is empty, else, evaluates to false. ]]
|
|
[[`sequence::template at<Seq, N>::type`][The type of element `N` in a sequence of type `Seq`]]
|
|
[[`sequence::template at<Seq, N>::call(seq)`][Element `N` in sequence `seq`]]
|
|
[[`sequence::template value_at<Sequence, N>::type`][The type of the `N`th element in a sequence of type `Seq`]]
|
|
]
|
|
|
|
[heading Include]
|
|
|
|
#include <boost/fusion/sequence/sequence_facade.hpp>
|
|
#include <boost/fusion/include/sequence_facade.hpp>
|
|
|
|
[heading Example]
|
|
A full working example using __sequence_facade__ is provided in triple.cpp in the extension examples.
|
|
|
|
[endsect]
|
|
|
|
[section Iterator Facade]
|
|
|
|
[heading Description]
|
|
The __iterator_facade__ template provides an intrusive mechanism for
|
|
producing a conforming Fusion iterator.
|
|
|
|
[heading Synopsis]
|
|
|
|
template<typename Derived, typename TravesalTag>
|
|
struct iterator_facade;
|
|
|
|
[heading Usage]
|
|
The user of iterator_facade derives his iterator type from a specialization of iterator_facade and passes the derived iterator type as the first template parameter. The second template parameter should be the traversal category of the iterator being implemented.
|
|
|
|
The user must implement the key expressions required by their iterator type.
|
|
|
|
[table Parameters
|
|
[[Name][Description]]
|
|
[[`iterator`, `It`, `It1`, `It2`][A type derived from __iterator_facade__]]
|
|
[[`N`][An __mpl_integral_constant__]]
|
|
]
|
|
|
|
[table Key Expressions
|
|
[[Expression][Result][Default]]
|
|
[[`iterator::template value_of<It>::type`][The element stored at iterator position `It`][None]]
|
|
[[`iterator::template deref<It>::type`][The type returned when dereferencing an iterator of type `It`][None]]
|
|
[[`iterator::template deref<It>::call(it)`][Dereferences iterator `it`][None]]
|
|
[[`iterator::template next<It>::type`][The type of the next element from `It`][None]]
|
|
[[`iterator::template next<It>::call(it)`][The next iterator after `it`][None]]
|
|
[[`iterator::template prior<It>::type`][The type of the next element from `It`][None]]
|
|
[[`iterator::template prior<It>::call(it)`][The next iterator after `it`][None]]
|
|
[[`iterator::template advance<It, N>::type`][The type of an iterator advanced `N` elements from `It`][Implemented in terms of `next` and `prior`]]
|
|
[[`iterator::template advance<It, N>::call(it)`][An iterator advanced `N` elements from `it`][Implemented in terms of `next` and `prior`]]
|
|
[[`iterator::template distance<It1, It2>::type`][The distance between iterators of type `It1` and `It2` as an __mpl_integral_constant__][None]]
|
|
[[`iterator::template distance<It1, It2>::call(it1, it2)`][The distance between iterator `it1` and `it2`][None]]
|
|
[[`iterator::template equal_to<It1, It2>::type`][Returns `mpl::true_` if `It1` is equal to `It2`, `mpl::false_` otherwise.][`boost::same_type<It1, It2>::type`]]
|
|
[[`iterator::template equal_to<It1, It2>::call(it1, it2)`][Returns a type convertible to `bool` that evaluates to `true` if `It1` is equal to `It2`, `false` otherwise.][`boost::same_type<It1, It2>::type()`]]
|
|
[[`iterator::template key_of<It>::type`][The key type associated with the element from `It`][None]]
|
|
[[`iterator::template value_of_data<It>::type`][The type of the data property associated with the element from `It`][None]]
|
|
[[`iterator::template deref_data<It>::type`][The type that will be returned by dereferencing the data property of the element from `It`][None]]
|
|
[[`iterator::template deref_data<It>::call(it)`][Deferences the data property associated with the element referenced by `it`][None]]
|
|
]
|
|
|
|
[heading Header]
|
|
|
|
#include <boost/fusion/iterator/iterator_facade.hpp>
|
|
#include <boost/fusion/include/iterator_facade.hpp>
|
|
|
|
[heading Example]
|
|
A full working example using __iterator_facade__ is provided in triple.cpp in the extension examples.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|