facade_tutorial.qbk
来自「Boost provides free peer-reviewed portab」· QBK 代码 · 共 508 行 · 第 1/2 页
QBK
508 行
[section:facade_tutorial Tutorial]In this section we'll walk through the implementation of a fewiterators using `iterator_facade`, based around the simpleexample of a linked list of polymorphic objects. This example wasinspired by a [@http://thread.gmane.org/gmane.comp.lib.boost.user/5100 `posting`]by Keith Macdonald on the [@http://www.boost.org/more/mailing_lists.htm#users `Boost-Users`]mailing list.[h2 The Problem]Say we've written a polymorphic linked list node base class: # include <iostream> struct node_base { node_base() : m_next(0) {} // Each node manages all of its tail nodes virtual ~node_base() { delete m_next; } // Access the rest of the list node_base* next() const { return m_next; } // print to the stream virtual void print(std::ostream& s) const = 0; // double the value virtual void double_me() = 0; void append(node_base* p) { if (m_next) m_next->append(p); else m_next = p; } private: node_base* m_next; };Lists can hold objects of different types by linking togetherspecializations of the following template: template <class T> struct node : node_base { node(T x) : m_value(x) {} void print(std::ostream& s) const { s << this->m_value; } void double_me() { m_value += m_value; } private: T m_value; };And we can print any node using the following streaming operator: inline std::ostream& operator<<(std::ostream& s, node_base const& n) { n.print(s); return s; }Our first challenge is to build an appropriate iterator over theselists.[h2 A Basic Iterator Using `iterator_facade`]We will construct a `node_iterator` class using inheritance from`iterator_facade` to implement most of the iterator's operations. # include "node.hpp" # include <boost/iterator/iterator_facade.hpp> class node_iterator : public boost::iterator_facade<...> { ... };[h2 Template Arguments for `iterator_facade`]`iterator_facade` has several template parameters, so we must decidewhat types to use for the arguments. The parameters are `Derived`,`Value`, `CategoryOrTraversal`, `Reference`, and `Difference`.[h3 `Derived`]Because `iterator_facade` is meant to be used with the CRTP[Cop95]_ the first parameter is the iterator class name itself,`node_iterator`.[h3 `Value`]The `Value` parameter determines the `node_iterator`\ 's`value_type`. In this case, we are iterating over `node_base`objects, so `Value` will be `node_base`.[h3 `CategoryOrTraversal`]Now we have to determine which `iterator traversal concept`_ our`node_iterator` is going to model. Singly-linked lists only haveforward links, so our iterator can't can't be a `bidirectionaltraversal iterator`_. Our iterator should be able to make multiplepasses over the same linked list (unlike, say, an`istream_iterator` which consumes the stream it traverses), so itmust be a `forward traversal iterator`_. Therefore, we'll pass`boost::forward_traversal_tag` in this position [#category]_... [#category] `iterator_facade` also supports old-style category tags, so we could have passed `std::forward_iterator_tag` here; either way, the resulting iterator's `iterator_category` will end up being `std::forward_iterator_tag`.[h3 `Reference`]The `Reference` argument becomes the type returned by`node_iterator`\ 's dereference operation, and will also be thesame as `std::iterator_traits<node_iterator>::reference`. Thelibrary's default for this parameter is `Value&`; since`node_base&` is a good choice for the iterator's `reference`type, we can omit this argument, or pass `use_default`.[h3 `Difference`]The `Difference` argument determines how the distance betweentwo `node_iterator`\ s will be measured and will also be thesame as `std::iterator_traits<node_iterator>::difference_type`.The library's default for `Difference` is `std::ptrdiff_t`, anappropriate type for measuring the distance between any twoaddresses in memory, and one that works for almost any iterator,so we can omit this argument, too.The declaration of `node_iterator` will therefore look somethinglike: # include "node.hpp" # include <boost/iterator/iterator_facade.hpp> class node_iterator : public boost::iterator_facade< node_iterator , node_base , boost::forward_traversal_tag > { ... };[h2 Constructors and Data Members]Next we need to decide how to represent the iterator's position.This representation will take the form of data members, so we'llalso need to write constructors to initialize them. The`node_iterator`\ 's position is quite naturally represented usinga pointer to a `node_base`. We'll need a constructor to build aniterator from a `node_base*`, and a default constructor tosatisfy the `forward traversal iterator`_ requirements [#default]_.Our `node_iterator` then becomes: # include "node.hpp" # include <boost/iterator/iterator_facade.hpp> class node_iterator : public boost::iterator_facade< node_iterator , node_base , boost::forward_traversal_tag > { public: node_iterator() : m_node(0) {} explicit node_iterator(node_base* p) : m_node(p) {} private: ... node_base* m_node; };.. [#default] Technically, the C++ standard places almost no requirements on a default-constructed iterator, so if we were really concerned with efficiency, we could've written the default constructor to leave `m_node` uninitialized.[h2 Implementing the Core Operations]The last step is to implement the `core operations`_ required bythe concepts we want our iterator to model. Referring to thetable__, we can see that the first three rows are applicablebecause `node_iterator` needs to satisfy the requirements for`readable iterator`_, `single pass iterator`_, and `incrementableiterator`_. __ `core operations`_We therefore need to supply `dereference`,`equal`, and `increment` members. We don't want these membersto become part of `node_iterator`\ 's public interface, so we canmake them private and grant friendship to`boost::iterator_core_access`, a "back-door" that`iterator_facade` uses to get access to the core operations: # include "node.hpp" # include <boost/iterator/iterator_facade.hpp> class node_iterator : public boost::iterator_facade< node_iterator , node_base , boost::forward_traversal_tag > { public: node_iterator() : m_node(0) {} explicit node_iterator(node_base* p) : m_node(p) {} private: friend class boost::iterator_core_access; void increment() { m_node = m_node->next(); } bool equal(node_iterator const& other) const { return this->m_node == other.m_node; } node_base& dereference() const { return *m_node; } node_base* m_node; };
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?