在reverse_iterator

时间:2015-06-24 20:27:40

标签: c++ inheritance iterator user-defined reverse-iterator

我正在为C ++ 11编写一个JSON类,请参阅http://github.com/nlohmann/json。我的中心数据结构是一个将JSON值类型(null,数组,对象,字符串,bool,数字)包装在一个联合中并通过一个漂亮的C ++接口提供它的类。由于数组(通过std::vector实现)和对象(std::map)带有自己的迭代器,我实现了一个"包装器" iterator将对operator++operator->的调用委托给相应的成员变量。此外,我实现了两个附加函数std::string key()来访问JSON对象的密钥,reference value()作为operator*()的别名。

到目前为止,非常好(请参阅https://github.com/nlohmann/json/blob/master/src/json.hpp了解完整的源代码)...

然后我想实施reverse_iteratorconst_reverse_iterator。这里出现了问题。

  • 如果我通过using reverse_iterator = std::reverse_iterator<iterator>;using const_reverse_iterator = std::reverse_iterator<const_iterator>;认识到它们,一切都很好,但key()或{{value()reverse_iterator功能不可用1}}对象。
  • 如果我实现自己的const_reverse_iteratorreverse_iterator,我需要再次实现整个班级。仅为class reverse_iterator : public std::reverse_iterator<typename basic_json::iterator>key()提供实现,但对于value()以及我希望使用operator++()适配器免费获得的所有其他内容也是不够的

我花了很长时间寻找答案,但是我发现所有参考文献要么抓不完整的玩具示例,要么得出结论:迭代器是努力的,人们应该转向Boost ......

所以这是我的问题:

  1. 如何从我的自定义类std::reverse_iterator创建reverse_iterator,以便它继承尽可能多的功能?
  2. 如果超出标准内容的继承行为无法自动生效,如何在不重复自己的情况下编写iterator
  3. 非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

不幸的是,我没有得到答案,所以这就是我所做的。也许一个丑陋的解决方案会激起某人发布更好的东西: - )

背景

所以我学到的第一件事是std::reverse_iterator只是封装了一个&#34; normal&#34;迭代器(称为current,可通过base()访问)并建立反向迭代器的关系,即#34;左边的一个元素&#34;而不是&#34;正常&#34;迭代器。

relationship between iterators and reverse iterators

(来自cppreference.com的图片)

通用解决方案

只要&#34;正常&#34;迭代器具有标准接口,不使用任何附加功能,即行

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
}

作品。

向迭代器添加更多功能

正如我在问题中写的那样,我将iterator课程扩展为另外两名成员key()value()。前者允许在迭代期间快速访问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 * ();
  }  
}

最棘手的部分是你需要实现&#34;逐个&#34;手动关系:

  1. 通过base()检索基础迭代器。
  2. 减少它指向&#34;右&#34; (左,实际......)元素。
  3. 调用所需的功能。
  4. 有了这个,我们差不多完成了。差不多,因为上面代码中的...。剩下要做的是将对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_iteratorconst_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

    我仍然希望看到避免重复大多数功能的解决方案,但这个对我来说已经足够了。由于我在很长一段时间内没有找到更好的东西,我决定分享它。

相关问题