📄 extension.qbk
字号:
[/============================================================================== Copyright (C) 2001-2007 Joel de Guzman, Dan Marsden, Tobias Schwinger 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 easilybe 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, weare 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 partylibrary, and therefore cannot be modified. We shall work through all thenecessary 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 thecorrect code for a given sequence type. In order to exploit the tagdispatching mechanism we must first declare a new tag type for themechanism 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 chosentag 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 conjuction with `boost::enable_if` to provide tagsupport for groups of related types. This feature is not necessaryfor 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 tothe 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` and1 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 weadd features to our implementation.[heading A first couple of instructive features]To start with, we will get the __result_of_value_of__ metafunction working. Todo this, we provide a specialization of the `boost::fusion::extension::value_of_impl` template forour 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 toprovide 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 __value_of__: template <typename Iterator> struct __value_of__ : extension::value_of_impl<typename detail::tag_of<Iterator>::type>:: template apply<Iterator> {};So __value_of__ uses __tag_dispatching__ to select an __mpl_metafunction_class__to provide its functionality. You will notice this pattern throughout theimplementation of Fusion.Ok, lets enable dereferencing of our iterator. In this case we must provide a suitablespecialization 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 alsoprovides 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 thesame way as the __value_of__ implementation. The runtime functionality usedby __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 referenceto the appropriate member of the underlying sequence. We also require a littlebit of metaprogramming to return `const` references if the underlying sequenceis const.[note Although there is a fair amount of left to do to produce a fully fledgedFusion sequence, __value_of__ and __deref__ illustrate all the signficant conceptsrequired. The remainder of the process is very repetitive, simply requiringimplementation of a suitable `xxxx_impl` for each feature `xxxx`.][heading Implementing the remaining iterator functionality]Ok, now we have seen the way __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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -