是否可以重用通常的迭代器来构建 const 迭代器?
Is it possible to reuse usual iterator to build const iterator?
研究
我找到了 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 belongs to implementation specifics" 案例之一。
模板可能是避免代码重复的唯一方法。但我不会让类型参数保持打开状态。我会简单地使用一个布尔参数,它被馈送到 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 迭代器构建。这类似于标准库的行为。
Also I'm not sure if this use of const is one of those "const belongs to implementation specifics" case.
您使用 const Node
的事实确实是一个实现细节。但只要它为您提供记录的类型行为(容器的 const 成员的迭代器),我就不会对此强调太多。
您可以安全地定义 class 模板 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 >;
中,后者变为空操作,只能有意调用(即使用语法 it.template operator iterator< value_type const > ()
)。
代码来自here——重写了libstdc++的红黑树
研究
我找到了 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 belongs to implementation specifics" 案例之一。
模板可能是避免代码重复的唯一方法。但我不会让类型参数保持打开状态。我会简单地使用一个布尔参数,它被馈送到 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 迭代器构建。这类似于标准库的行为。
Also I'm not sure if this use of const is one of those "const belongs to implementation specifics" case.
您使用 const Node
的事实确实是一个实现细节。但只要它为您提供记录的类型行为(容器的 const 成员的迭代器),我就不会对此强调太多。
您可以安全地定义 class 模板 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 >;
中,后者变为空操作,只能有意调用(即使用语法 it.template operator iterator< value_type const > ()
)。
代码来自here——重写了libstdc++的红黑树