是否可以重用通常的迭代器来构建常量迭代器?

Is it possible to reuse usual iterator to build const iterator?

本文关键字:迭代器 构建 常量 是否      更新时间:2023-10-16

研究

我找到了这个古老的答案。我想知道解决方案是否仍然有效,或者是否有新的、更有效的方法可以做到这一点。

背景

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

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 属于实现细节"的情况之一。

模板可能是避免代码重复的唯一方法。但我不会让类型参数保持打开状态。我只需使用馈送到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 成员的迭代器(,我就不会对此强调太多。

您可以安全地定义类模板template< typename value_type > iterator按值类型(const或非const(参数化,并将运算符转换为const版本(即operator interator< value_type const > () 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< value_type const >;,后者变成了no-op,只能被有意地调用(即使用语法it.template operator iterator< value_type const > ()(。

代码是从这里给出的 - 重写libstdc++的红黑树。