1 [/==============================================================================
2 Copyright (C) 2001-2011 Joel de Guzman
3 Copyright (C) 2006 Dan Marsden
5 Use, modification and distribution is subject to the Boost Software
6 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 http://www.boost.org/LICENSE_1_0.txt)
8 ===============================================================================/]
11 [section:ext_full The Full Extension Mechanism]
13 The Fusion library is designed to be extensible, new sequences types can easily
14 be added. In fact, the library support for `std::pair`, `boost::array` and __mpl__
15 sequences is entirely provided using the extension mechanism.
17 The process for adding a new sequence type to Fusion is:
19 # Enable the __tag_dispatching__ mechanism used by Fusion for your sequence type
20 # Design an iterator type for the sequence
21 # Provide specialized behaviour for the intrinsic operations of the new Fusion sequence
25 In order to illustrate enabling a new sequence type for use with Fusion, we
26 are going to use the type:
42 We are going to pretend that this type has been provided by a 3rd party
43 library, and therefore cannot be modified. We shall work through all the
44 necessary steps to enable `example_struct` to serve as an __associative_sequence__
45 as described in the __quick_start__ guide.
47 [heading Enabling Tag Dispatching]
49 The Fusion extensibility mechanism uses __tag_dispatching__ to call the
50 correct code for a given sequence type. In order to exploit the tag
51 dispatching mechanism we must first declare a new tag type for the
52 mechanism to use. For example:
55 struct example_sequence_tag; // Only definition needed
58 Next we need to enable the `traits::tag_of` metafunction to return our newly chosen
59 tag type for operations involving our sequence. This is done by specializing
60 `traits::tag_of` for our sequence type.
62 #include <boost/fusion/support/tag_of_fwd.hpp>
63 #include <boost/fusion/include/tag_of_fwd.hpp>
65 namespace boost { namespace fusion { namespace traits {
67 struct tag_of<example_struct>
69 typedef example::example_sequence_tag type;
73 `traits::tag_of` also has a second template argument,
74 that can be used in conjunction with `boost::enable_if` to provide tag
75 support for groups of related types. This feature is not necessary
76 for our sequence, but for an example see the code in:
78 #include <boost/fusion/adapted/array/tag_of.hpp>
79 #include <boost/fusion/include/tag_of.hpp>
81 [heading Designing a suitable iterator]
83 We need an iterator to describe positions, and provide access to
84 the data within our sequence. As it is straightforward to do,
85 we are going to provide a random access iterator in our example.
87 We will use a simple design, in which the 2 members of
88 `example_struct` are given numbered indices, 0 for `name` and
89 1 for `age` respectively.
91 template<typename Struct, int Pos>
92 struct example_struct_iterator
93 : boost::fusion::iterator_base<example_struct_iterator<Struct, Pos> >
95 BOOST_STATIC_ASSERT(Pos >=0 && Pos < 3);
96 typedef Struct struct_type;
97 typedef boost::mpl::int_<Pos> index;
98 typedef boost::fusion::random_access_traversal_tag category;
100 example_struct_iterator(Struct& str)
106 A quick summary of the details of our iterator:
108 # The iterator is parameterized by the type it is iterating over, and the index of the current element.
109 # The typedefs `struct_type` and `index` provide convenient access to information we will need later in
111 # The typedef `category` allows the `traits::__category_of__` metafunction to establish
112 the traversal category of the iterator.
113 # The constructor stores a reference to the `example_struct` being iterated over.
115 We also need to enable __tag_dispatching__ for our iterator type, with another specialization of
118 In isolation, the iterator implementation is pretty dry. Things should become clearer as we
119 add features to our implementation.
121 [heading A first couple of instructive features]
123 To start with, we will get the __result_of_value_of__ metafunction working. To
124 do this, we provide a specialization of the `boost::fusion::extension::value_of_impl` template for
125 our iterator's tag type.
128 struct value_of_impl<example::example_struct_iterator_tag>
130 template<typename Iterator>
133 template<typename Struct>
134 struct apply<example::example_struct_iterator<Struct, 0> >
136 typedef std::string type;
139 template<typename Struct>
140 struct apply<example::example_struct_iterator<Struct, 1> >
146 The implementation itself is pretty simple, it just uses 2 partial specializations to
147 provide the type of the 2 different members of `example_struct`, based on the index of the iterator.
149 To understand how `value_of_impl` is used by the library we will look at the implementation of __result_of_value_of__:
151 template <typename Iterator>
153 : extension::value_of_impl<typename detail::tag_of<Iterator>::type>::
154 template apply<Iterator>
157 So __result_of_value_of__ uses __tag_dispatching__ to select an __mpl_metafunction_class__
158 to provide its functionality. You will notice this pattern throughout the
159 implementation of Fusion.
161 Ok, lets enable dereferencing of our iterator. In this case we must provide a suitable
162 specialization of `deref_impl`.
165 struct deref_impl<example::example_struct_iterator_tag>
167 template<typename Iterator>
170 template<typename Struct>
171 struct apply<example::example_struct_iterator<Struct, 0> >
173 typedef typename mpl::if_<
174 is_const<Struct>, std::string const&, std::string&>::type type;
177 call(example::example_struct_iterator<Struct, 0> const& it)
179 return it.struct_.name;
183 template<typename Struct>
184 struct apply<example::example_struct_iterator<Struct, 1> >
186 typedef typename mpl::if_<
187 is_const<Struct>, int const&, int&>::type type;
190 call(example::example_struct_iterator<Struct, 1> const& it)
192 return it.struct_.age;
198 The use of `deref_impl` is very similar to that of `value_of_impl`, but it also
199 provides some runtime functionality this time via the `call` static member function.
200 To see how `deref_impl` is used, lets have a look at the implementation of __deref__:
204 template <typename Iterator>
206 : extension::deref_impl<typename detail::tag_of<Iterator>::type>::
207 template apply<Iterator>
211 template <typename Iterator>
212 typename result_of::deref<Iterator>::type
213 __deref__(Iterator const& i)
215 typedef result_of::deref<Iterator> deref_meta;
216 return deref_meta::call(i);
219 So again __result_of_deref__ uses __tag_dispatching__ in exactly the
220 same way as the __result_of_value_of__ implementation. The runtime functionality used
221 by __deref__ is provided by the `call` static function of the selected
222 __mpl_metafunction_class__.
224 The actual implementation of `deref_impl` is slightly more complex than that of `value_of_impl`.
225 We also need to implement the `call` function, which returns a reference
226 to the appropriate member of the underlying sequence. We also require a little
227 bit of metaprogramming to return `const` references if the underlying sequence
230 [note Although there is a fair amount of left to do to produce a fully fledged
231 Fusion sequence, __result_of_value_of__ and __deref__ illustrate all the significant concepts
232 required. The remainder of the process is very repetitive, simply requiring
233 implementation of a suitable `xxxx_impl` for each feature `xxxx`.
236 [heading Implementing the remaining iterator functionality]
238 Ok, now we have seen the way __result_of_value_of__ and __deref__ work, everything else will work
239 in pretty much the same way. Lets start with forward iteration,
240 by providing a `next_impl`:
243 struct next_impl<example::example_struct_iterator_tag>
245 template<typename Iterator>
248 typedef typename Iterator::struct_type struct_type;
249 typedef typename Iterator::index index;
250 typedef example::example_struct_iterator<struct_type, index::value + 1> type;
253 call(Iterator const& i)
255 return type(i.struct_);
260 This should be very familiar from our `deref_impl` implementation, we will be
261 using this approach again and again now. Our design is simply to increment
262 the `index` counter to move on to the next element. The various other iterator
263 manipulations we need to perform will all just involve simple calculations
264 with the `index` variables.
266 We also need to provide a suitable `equal_to_impl` so that iterators can be
267 correctly compared. A __bidirectional_iterator__ will also need an implementation of `prior_impl`. For a
268 __random_access_iterator__ `distance_impl` and `advance_impl` also need to be provided
269 in order to satisfy the necessary complexity guarantees. As our iterator is
270 a __random_access_iterator__ we will have to implement all of these functions.
272 Full implementations of `prior_impl`, `advance_impl`, `distance_impl` and `equal_to_impl` are
273 provided in the example code.
275 [heading Implementing the intrinsic functions of the sequence]
277 In order that Fusion can correctly identify our sequence as a Fusion sequence, we
278 need to enable `is_sequence` for our sequence type. As usual we just create
279 an `impl` type specialized for our sequence tag:
282 struct is_sequence_impl<example::example_sequence_tag>
285 struct apply : mpl::true_ {};
288 We've some similar formalities to complete, providing `category_of_impl` so Fusion
289 can correctly identify our sequence type, and `is_view_impl` so Fusion can correctly
290 identify our sequence as not being a __view__ type. Implementations are
291 provide in the example code.
293 Now we've completed some formalities, on to more interesting features. Lets get
294 __begin__ working so that we can get an iterator to start accessing the data in
298 struct begin_impl<example::example_sequence_tag>
300 template<typename Sequence>
303 typedef example::example_struct_iterator<Sequence, 0> type;
313 The implementation uses the same ideas we have applied throughout, in this case
314 we are just creating one of the iterators we developed earlier, pointing to the
315 first element in the sequence. The implementation of __end__ is very similar, and
316 is provided in the example code.
318 For our __random_access_sequence__ we will also need to implement `size_impl`,
319 `value_at_impl` and `at_impl`.
321 [heading Enabling our type as an associative sequence]
323 In order for `example_struct` to serve as an associative forward sequence,
324 we need to adapt the traversal category of our sequence and our iterator
325 accordingly and enable 3 intrinsic sequence lookup features, __at_key__,
326 __result_of_value_at_key__ and __has_key__. We also need to enable 3 iterator lookup
327 features, __result_of_key_of__, __result_of_value_of_data__ and __deref_data__.
329 To implement `at_key_impl` we need to associate the `fields::name` and `fields::age`
330 types described in the __quick_start__ guide with the appropriate members of `example_struct`.
331 Our implementation is as follows:
334 struct at_key_impl<example::example_sequence_tag>
336 template<typename Sequence, typename Key>
339 template<typename Sequence>
340 struct apply<Sequence, fields::name>
342 typedef typename mpl::if_<
345 std::string&>::type type;
354 template<typename Sequence>
355 struct apply<Sequence, fields::age>
357 typedef typename mpl::if_<
370 Its all very similar to the implementations we've seen previously,
371 such as `deref_impl` and `value_of_impl`. Instead of identifying
372 the members by index or position, we are now selecting them using
373 the types `fields::name` and `fields::age`. The implementations of
374 the other functions are equally straightforward, and are provided in
379 We've now worked through the entire process for adding a new random
380 access sequence and we've also enabled our type to serve as an associative
381 sequence. The implementation was slightly long-winded, but followed
382 a simple repeating pattern.
384 The support for `std::pair`, __mpl__ sequences, and `boost::array` all
385 use the same approach, and provide additional examples of the approach
386 for a variety of types.
390 [section Sequence Facade]
392 [heading Description]
393 The __sequence_facade__ template provides an intrusive mechanism for
394 producing a conforming Fusion sequence.
397 template<typename Derived, typename TravesalTag, typename IsView = mpl::false_>
398 struct sequence_facade;
401 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.
403 The user must implement the key expressions required by their sequence type.
406 [[Name][Description]]
407 [[`sequence`, `Seq`][A type derived from __sequence_facade__]]
408 [[`N`][An __mpl_integral_constant__]]
411 [table Key Expressions
412 [[Expression][Result]]
413 [[`sequence::template begin<Seq>::type`][The type of an iterator to the beginning of a sequence of type `Seq`]]
414 [[`sequence::template begin<Seq>::call(seq)`][An iterator to the beginning of sequence `seq`]]
415 [[`sequence::template end<Seq>::type`][The type of an iterator to the end of a sequence of type `Seq`]]
416 [[`sequence::template end<Seq>::call(seq)`][An iterator to the end of sequence `seq`]]
417 [[`sequence::template size<Seq>::type`][The size of a sequence of type `Seq` as an __mpl_integral_constant__]]
418 [[`sequence::template size<Seq>::call(seq)`][The size of sequence `seq`]]
419 [[`sequence::template empty<Seq>::type`][Returns `mpl::true_` if `Seq` has zero elements, `mpl::false_` otherwise.]]
420 [[`sequence::template empty<Seq>::call`][Returns a type convertible to `bool` that evaluates to true if the sequence is empty, else, evaluates to false. ]]
421 [[`sequence::template at<Seq, N>::type`][The type of element `N` in a sequence of type `Seq`]]
422 [[`sequence::template at<Seq, N>::call(seq)`][Element `N` in sequence `seq`]]
423 [[`sequence::template value_at<Sequence, N>::type`][The type of the `N`th element in a sequence of type `Seq`]]
428 #include <boost/fusion/sequence/sequence_facade.hpp>
429 #include <boost/fusion/include/sequence_facade.hpp>
432 A full working example using __sequence_facade__ is provided in triple.cpp in the extension examples.
436 [section Iterator Facade]
438 [heading Description]
439 The __iterator_facade__ template provides an intrusive mechanism for
440 producing a conforming Fusion iterator.
444 template<typename Derived, typename TravesalTag>
445 struct iterator_facade;
448 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.
450 The user must implement the key expressions required by their iterator type.
453 [[Name][Description]]
454 [[`iterator`, `It`, `It1`, `It2`][A type derived from __iterator_facade__]]
455 [[`N`][An __mpl_integral_constant__]]
458 [table Key Expressions
459 [[Expression][Result][Default]]
460 [[`iterator::template value_of<It>::type`][The element stored at iterator position `It`][None]]
461 [[`iterator::template deref<It>::type`][The type returned when dereferencing an iterator of type `It`][None]]
462 [[`iterator::template deref<It>::call(it)`][Dereferences iterator `it`][None]]
463 [[`iterator::template next<It>::type`][The type of the next element from `It`][None]]
464 [[`iterator::template next<It>::call(it)`][The next iterator after `it`][None]]
465 [[`iterator::template prior<It>::type`][The type of the next element from `It`][None]]
466 [[`iterator::template prior<It>::call(it)`][The next iterator after `it`][None]]
467 [[`iterator::template advance<It, N>::type`][The type of an iterator advanced `N` elements from `It`][Implemented in terms of `next` and `prior`]]
468 [[`iterator::template advance<It, N>::call(it)`][An iterator advanced `N` elements from `it`][Implemented in terms of `next` and `prior`]]
469 [[`iterator::template distance<It1, It2>::type`][The distance between iterators of type `It1` and `It2` as an __mpl_integral_constant__][None]]
470 [[`iterator::template distance<It1, It2>::call(it1, it2)`][The distance between iterator `it1` and `it2`][None]]
471 [[`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`]]
472 [[`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()`]]
473 [[`iterator::template key_of<It>::type`][The key type associated with the element from `It`][None]]
474 [[`iterator::template value_of_data<It>::type`][The type of the data property associated with the element from `It`][None]]
475 [[`iterator::template deref_data<It>::type`][The type that will be returned by dereferencing the data property of the element from `It`][None]]
476 [[`iterator::template deref_data<It>::call(it)`][Deferences the data property associated with the element referenced by `it`][None]]
481 #include <boost/fusion/iterator/iterator_facade.hpp>
482 #include <boost/fusion/include/iterator_facade.hpp>
485 A full working example using __iterator_facade__ is provided in triple.cpp in the extension examples.