从 reverse_iterator 中的用户定义的迭代器继承所有函数
Posted
技术标签:
【中文标题】从 reverse_iterator 中的用户定义的迭代器继承所有函数【英文标题】:Inherit all functions from user-defined iterator in reverse_iterator 【发布时间】:2015-06-24 20:27:39 【问题描述】:我正在为 C++11 编写 JSON 类,请参阅 http://github.com/nlohmann/json。我的中心数据结构是一个类,将 JSON 值类型(null、array、object、string、bool、number)包装在一个联合中,并通过一个不错的 C++ 接口提供它。由于数组(通过std::vector
实现)和对象(std::map
)带有它们自己的迭代器,因此我实现了一个“包装器”迭代器,它将对operator++
或operator->
的调用委托给各自的成员变量。此外,我实现了两个附加函数std::string key()
来访问 JSON 对象的键,并实现了 reference value()
作为 operator*()
的别名。
到目前为止,一切都很好(完整的源代码参见https://github.com/nlohmann/json/blob/master/src/json.hpp)...
然后我想实现reverse_iterator
和const_reverse_iterator
。问题就从这里开始了。
using reverse_iterator = std::reverse_iterator<iterator>;
和using const_reverse_iterator = std::reverse_iterator<const_iterator>;
实现它们,一切都很好,但是key()
和value()
函数不适用于reverse_iterator
或const_reverse_iterator
对象。
如果我像class reverse_iterator : public std::reverse_iterator<typename basic_json::iterator>
一样实现我自己的类reverse_iterator
,我需要再次实现整个类。仅提供key()
和value()
的实现是不够的,还提供operator++()
以及我希望使用std::reverse_iterator
适配器免费获得的所有其他内容。
我花了相当长的时间寻找答案,但我发现的所有参考资料要么只是触及了不完整的玩具示例的表面,要么得出的结论是迭代器是一项艰苦的工作,应该转向 Boost...
所以这是我的问题:
-
如何从我的自定义类
iterator
创建一个 reverse_iterator
以便它尽可能多地继承功能?
如果继承超出标准内容的行为不能自动工作,我如何编写reverse_iterator
而不完全重复自己?
非常感谢任何帮助!
【问题讨论】:
【参考方案1】:很遗憾,我没有收到答案,所以这就是我所做的。也许一个丑陋的解决方案会激起某人发布更好的东西:-)
背景
所以我学到的第一件事是std::reverse_iterator
只是封装了一个“普通”迭代器(称为current
,可通过base()
访问)并建立反向迭代器与“一个元素”的关系比“正常”迭代器更靠左”。
(图片来自cppreference.com)
通用解决方案
只要“普通”迭代器具有标准接口并且不使用任何附加功能,行
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
足以自动将您自己的迭代器类转换为反向迭代器。
和成员函数
reverse_iterator rbegin() return reverse_iterator(end());
reverse_iterator rend() return reverse_iterator(begin());
const_reverse_iterator crbegin() const return const_reverse_iterator(cend());
const_reverse_iterator crend() const return const_reverse_iterator(cbegin());
反向迭代是可能的,例如像这样的代码
for (my_container::reverse_iterator rit = c.rbegin(); rit != c.rend(); ++it)
// rit will iterator container c in reverse order
有效。
向迭代器添加更多功能
正如我在问题中所写,我用两个额外的成员 key()
和 value()
扩展了 iterator
类。前者允许在迭代期间快速访问 JSON 对象的键。后者是写it.value()
而不是*it
的别名。不幸的是,上述方法并没有将这些函数继承给reverse_iterator
。
为了丰富用户定义的反向迭代器,我们需要继承 std::reverse_iterator<iterator>
并将调用委托给基迭代器。不幸的是,我发现除了手动执行此操作之外没有其他方法。对于上述功能,如下所示:
class reverse_iterator : public std::reverse_iterator<iterator>
...
std::string key() const
auto it = --this->base();
return it.key();
reference value() const
auto it = --this->base();
return it.operator * ();
最棘手的部分是您需要手动实现“off-by-one”关系:
-
通过
base()
检索基迭代器。
将其递减以指向“右”(实际上是左...)元素。
调用所需的函数。
这样,我们就快完成了。几乎,因为上面代码中的...
。剩下要做的就是将所有其他对函数(如operator++
)的调用委托给基类。我现在找到了让其他人参加这个无聊代表团的方法。
所以类包含类似的代码
using base_iterator = std::reverse_iterator<iterator>;
reverse_iterator operator++(int)
return base_iterator::operator++(1);
reverse_iterator& operator++()
base_iterator::operator++();
return *this;
(注意base_iterator
的定义。)
就是这样。我们现在有用户定义的反向迭代器,允许我们编码
for (my_container::reverse_iterator rit = c.rbegin(); rit != c.rend(); ++it)
std::cout << rit.key() << '\n';
清理
在 Github 上的一次讨论中,gregmarr 提议将reverse_iterator
和const_reverse_iterator
类组合成一个模板类,例如
template<typename Base>
class json_reverse_iterator : public std::reverse_iterator<Base>
public:
/// shortcut to the reverse iterator adaptor
using base_iterator = std::reverse_iterator<Base>;
/// the reference type for the pointed-to element
using reference = typename Base::reference;
/// create reverse iterator from iterator
json_reverse_iterator(const typename base_iterator::iterator_type& it)
: base_iterator(it)
/// create reverse iterator from base class
json_reverse_iterator(const base_iterator& it) : base_iterator(it)
...
这样可以写
using reverse_iterator = json_reverse_iterator<iterator>;
using const_reverse_iterator = json_reverse_iterator<const_iterator>;
要快乐。
完整示例
完整代码见here。
我仍然希望看到一个避免重复大多数功能的解决方案,但这个对我来说已经足够了。由于我很久没有找到更好的东西,所以我决定分享它。
【讨论】:
以上是关于从 reverse_iterator 中的用户定义的迭代器继承所有函数的主要内容,如果未能解决你的问题,请参考以下文章
C++ rbegin 修改reverse_iterator的地址
对于std :: reverse_iterator c ++,operator!=不明确