4

我有一个包含和管理一系列对象的类。为了避免在允许遍历它们的同时泄露这些对象的存储方式,我决定使用类型擦除boost::any_iterator

 using my_erased_type_iterator = boost::range_detail::any_iterator<
    MyClass,
    boost::bidirectional_traversal_tag,
    MyClass&, 
    std::ptrdiff_t>;

我定义了一个函数Begin()and End()in MyClass,它简单地将容器的begin()andend()函数返回为my_erased_type_iterator. 它完全按照我的意愿工作,除了我在's 的接口MyClass中公开的功能外,没有人知道我正在使用向量来存储对象,也没有人可以访问容器。Myclass

现在,由于多种原因,我需要对对象进行反向迭代。我还需要知道反向迭代器之后的下一个元素(类似于调用std::next()普通迭代器,这对于反向迭代器来说已经不是那么简单了),并且我可能还需要调用erase()该反向迭代器上的函数。

所以对于我的问题:是否有一种优雅的方式来使用类型擦除和反向迭代器(以及正向和反向的 const 版本)?我应该使用前向类型擦除迭代器并向后迭代吗?我突然想到我可能以错误的方式解决这个问题,所以我愿意接受任何建议或在需要时澄清我的问题。

4

2 回答 2

1

只需反转类型擦除的迭代器。

这暴露.base()了 ,这意味着擦除几乎与擦除类型擦除的向前一样容易。

顺便说一句,您的设计具有(根据我的经验)边际收益的性能成本。底层容器的 iterafor invalidadion 规则仍然适用,所以你的类的用户必须知道底层容器是什么!(或者,他们也可能知道这么多)。换出容器不会提供足够相似的行为,因此尽管您尝试隐藏它的成本相当高,但您的容器仍被锁定。

于 2016-01-27T01:27:39.403 回答
1

请注意,这any_iterator是一个实现细节。

我将首先回答您的直接问题,然后any_range<>按照 Boost Range 的公共 API 的意图展示该方法。

1.make_reverse_iterator

您可以简单地使用该make_reverse_iterator设施

Live On Coliru

#include <boost/range.hpp>
#include <boost/range/any_range.hpp>

struct MyClass {
    int i;
};

using my_erased_type_iterator = boost::range_detail::any_iterator<
    MyClass,
    boost::bidirectional_traversal_tag,
    MyClass&, 
    std::ptrdiff_t>;

#include <iostream>
#include <vector>

int main() {
    using namespace boost;
    std::vector<MyClass> const v { {1}, {2}, {3}, {4} };

    for (auto& mc : make_iterator_range(
                make_reverse_iterator(v.end()),
                make_reverse_iterator(v.begin())))
    {
        std::cout << mc.i << " ";
    }
}

印刷

4 3 2 1 

2.reversed范围适配器:

或者,您可以采用全系列风格并使用any_range<>

Live On Coliru

int main() {
    std::vector<MyClass> const v { {1}, {2}, {3}, {4} };

    boost::any_range_type_generator<decltype(v)>::type x = reverse(v);

    for (my_erased_type_const_iterator f = boost::begin(x), l = boost::end(x); f!=l; ++f) {
        std::cout << f->i << " ";
    }

}
于 2016-01-26T23:51:33.797 回答