3

我正在为 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_iteratorand const_reverse_iterator。问题就从这里开始了。

  • 如果我通过using reverse_iterator = std::reverse_iterator<iterator>;and实现它们using const_reverse_iterator = std::reverse_iterator<const_iterator>;,一切都很好,但是函数key()andvalue()不适用于reverse_iteratororconst_reverse_iterator对象。
  • 如果我实现我自己的类reverse_iteratorclass reverse_iterator : public std::reverse_iterator<typename basic_json::iterator>我需要再次实现整个类。key()仅提供and的实现是不够的value(),还operator++()包括我希望使用std::reverse_iterator适配器免费获得的所有其他东西。

我花了很多时间寻找答案,但我发现的所有参考资料要么只是触及不完整的玩具示例的表面,要么得出的结论是迭代器是一项艰苦的工作,应该转向 Boost ......

所以这是我的问题:

  1. 如何reverse_iterator从我的自定义类创建一个,iterator以便它继承尽可能多的功能?
  2. 如果继承标准东西之外的行为不能自动工作,我怎么能在reverse_iterator不完全重复自己的情况下编写一个?

任何帮助是极大的赞赏!

4

1 回答 1

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
}

作品。

向迭代器添加更多功能

正如我在问题中所写,我iterator用两个额外的成员扩展了这个类,key()并且value(). 前者允许在迭代期间快速访问 JSON 对象的键。后者是 writeit.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 * ();
  }  
}

最棘手的部分是您需要手动实现“一对一”关系:

  1. 通过 检索基本迭代器base()
  2. 将其递减以指向“右”(实际上是左...)元素。
  3. 调用所需的函数。

有了这个,我们几乎完成了。几乎,因为...在上面的代码中。剩下要做的就是将所有其他调用委托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>;

并且要快乐。

完整示例

有关完整代码,请参见此处

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

于 2015-07-21T20:07:23.120 回答