【问题标题】:Is it possible to reuse usual iterator to build const iterator?是否可以重用通常的迭代器来构建 const 迭代器?
【发布时间】:2018-01-29 00:40:16
【问题描述】:

研究

我找到了this old answer。我想知道该解决方案是否仍然有效,或者是否有更有效的新方法。

背景

假设我有一个像下面这样的迭代器(细节并不重要,只是它很大):

    class inorder_iterator : public std::iterator<std::forward_iterator_tag, token>
    {
        friend syntax_tree;

        node* current_node;
        std::stack<node*> prev_nodes;
        //std::stack<node*> visited_nodes;
        std::map<node*, bool> visited;
    public:
        inorder_iterator();

        inorder_iterator& operator++();
        inorder_iterator operator++(int);

        token& operator*();
        const token& operator*() const;

        token* operator->();
        const token* operator->() const;

        friend bool operator==(const inorder_iterator lhs, const inorder_iterator rhs);
        friend bool operator!=(const inorder_iterator lhs, const inorder_iterator rhs);

    private:
        inorder_iterator(node* current);
        node* find_leftmost_node(node* from);
    };

问题

成员函数声明的实现大小合理,但我想重用当前的迭代器以减少代码重复。

想法

想到的第一个想法是模板化 node 类型,所以我可以通过 const node 使其成为 const 迭代器,但这听起来很可疑

template <typename Node>
//replace every occurrence of node with Node
// and use decltype(node.tk) instead of token everywhere

我也不确定const 的这种使用是否属于“const 属于实现细节”的情况之一。

【问题讨论】:

    标签: c++ c++14 code-reuse const-iterator


    【解决方案1】:

    模板可能是避免代码重复的唯一方法。但我不会让类型参数保持打开状态。我会简单地使用一个布尔参数,该参数被馈送到std::conditional 以确定类型:

    template<bool IsConst> class iter_impl {
      using value_type = std::conditional_t<IsConst, Node const, Node>;
    };
    

    容器的两个迭代器类型可以是几个别名,或者如果你想要真正不同的类型,可以是几个从模板继承的类。像这样:

    struct const_iterator : iter_impl<true> {};
    struct iterator : iter_impl<false> {};
    

    使用两个新类的好处是,您可以为const_iterator 定义一个转换构造函数,允许从非常量迭代器构建它。这类似于标准库的行为。

    我也不确定 const 的这种使用是否属于“const 属于实现细节”的情况之一。

    您使用const Node 的事实确实是一个实现细节。但只要它为您提供记录在案的类型行为(容器的 const 成员的迭代器),我不会对此过分强调。

    【讨论】:

    • 感谢您的好回答。顺便说一句,你也会成为 CodeReview 的伟大贡献者!
    • @Incomputable - 谢谢 :) 我最近把脚趾浸入了那里的水中。到目前为止一切顺利。
    【解决方案2】:

    您可以安全地定义通过值类型(const 或非const)参数化的类模板template&lt; typename value_type &gt; iterator,并将转换运算符转换为const 版本(即operator interator&lt; value_type const &gt; () const):

    template< typename type >
    struct node
            : node_base
    {
    
        union { type value; };
    
        node() noexcept { ; }
    
        node(node const &) = delete;
        node(node &&) = delete;
        void operator = (node const &) = delete;
        void operator = (node &&) = delete;
    
        ~node() { ; }
    
        type * pointer() noexcept { return &value; }
    
    };
    
    template< typename type >
    struct tree_iterator
    {
    
        using value_type = type;
        using reference = type &;
        using pointer = type *;
    
        using iterator_category = std::bidirectional_iterator_tag;
        using difference_type = std::ptrdiff_t;
    
        using node_type = node< value_type >;
        using node_pointer = node_type *;
    
        base_pointer p = nullptr;
    
        pointer operator -> () const noexcept { return node_pointer(p)->pointer(); }
        reference operator * () const noexcept { return *operator -> (); }
    
        tree_iterator & operator ++ () noexcept { p = increment(p); return *this; }
        tree_iterator operator ++ (int) noexcept { return {std::exchange(p, increment(p))}; }
    
        tree_iterator & operator -- () noexcept { p = decrement(p); return *this; }
        tree_iterator operator -- (int) noexcept { return {std::exchange(p, decrement(p))}; }
    
        bool operator == (tree_iterator const & it) const noexcept { return p == it.p; }
        bool operator != (tree_iterator const & it) const noexcept { return !operator == (it); }
    
        operator tree_iterator< type const > () const { return {p}; }
    
    };
    

    using const_iterator = iterator&lt; value_type const &gt;; 中,后者变为无操作并且只能被有意调用(即使用语法it.template operator iterator&lt; value_type const &gt; ())。

    代码来自here——重写libstdc++的红黑树。

    【讨论】:

    • 感谢您提供另一个解决方案,但我相信 StoryTeller 的解决方案目前更适合我。
    猜你喜欢
    • 1970-01-01
    • 2015-09-04
    • 2011-01-18
    • 2015-12-09
    • 2018-02-16
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多