C++ 使用带类型擦除的反向迭代器

C++ 使用带类型擦除的反向迭代器,c++,boost,iterator,reverse-iterator,boost-type-erasure,C++,Boost,Iterator,Reverse Iterator,Boost Type Erasure,我有一个类,它包含并管理一系列对象。为了避免在允许遍历对象时泄漏这些对象的存储方式,我决定使用boost::any_iterator使用类型擦除 using my_erased_type_iterator = boost::range_detail::any_iterator< MyClass, boost::bidirectional_traversal_tag, MyClass&, std::ptrdiff_t>; 使用我的擦除类型迭

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

 using my_erased_type_iterator = boost::range_detail::any_iterator<
    MyClass,
    boost::bidirectional_traversal_tag,
    MyClass&, 
    std::ptrdiff_t>;
使用我的擦除类型迭代器=boost::range\u detail::any\u迭代器<
我的班级,
boost::双向遍历标记,
MyClass&,
标准::ptrdiff_t>;
我在
MyClass
中定义了一个函数
Begin()
End()
,它将容器的
Begin()
End()
函数作为
my_erased_type_迭代器
返回。它完全按照我想要的方式工作,除了
MyClass
之外,没有人知道我正在使用向量存储对象,也没有人知道除了我在
MyClass
的接口中公开的函数之外,它们还可以访问容器

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


那么对于我的问题:有没有一种优雅的方法可以将类型擦除与反向迭代器(以及forward和reverse的const版本)一起使用呢?我应该使用前向类型擦除迭代器,而使用后向迭代器吗?我突然想到,我可能以错误的方式解决了这个问题,因此如果需要,我愿意接受任何建议或澄清我的问题。

请注意,
任何迭代器都是一个实现细节

我将首先回答您的直接问题,然后按照Boost range的公共API的预期,展示使用
任意_范围的方法

1. <代码>生成反向迭代器
您只需从中使用
make\u reverse\u迭代器
功能即可

  • 标准c++14
  • 促进

#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 << " ";
    }
}
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 << " ";
    }

}

2. <代码>反向
范围适配器: 或者,您可以选择全量程样式并使用
任意量程

#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 << " ";
    }
}
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 << " ";
    }

}
intmain(){
向量常数v{{1},{2},{3},{4};
升压::任意量程类型发电机::类型x=反向(v);
对于(我的已擦除类型常量迭代器f=boost::begin(x),l=boost::end(x);f!=l;++f){

std::cout i只需反转类型擦除的迭代器

这将公开
.base()
,这意味着擦除几乎和擦除前向擦除的类型一样容易


另一方面,根据我的经验,您的设计具有边际效益的性能成本。基础容器的iterafor invalidadion规则仍然适用,因此您的类的用户必须知道基础容器是什么!(或者,他们也可能知道这么多)。调出容器不会提供足够相似的行为,因此,尽管您试图隐藏它的成本相当高,但您的容器仍被锁定。

添加了关于库实现细节的警告,以及一个更干净的
任意范围的
版本。不支持擦除?@Yakk您的意思是什么?在我的示例中,它们是常量迭代器,是nd双向/随机,具体取决于使用情况。是否需要澄清?OP希望使用反向迭代器擦除元素,作为擦除的位置(确切的细节是模糊的)。“作为擦除的位置”-我不知道你的句子的意思,抱歉,你知道你的选择有性能成本和迭代器无效规则(每个容器都非常独特)泄漏您正在使用的容器?(当您的迭代器无效时是您接口的一部分)啊。我现在看到与
erase()
-由于所有的“类型擦除”,我错过了它。您不能将
erase
与“烘焙”迭代器一起使用,因为没有(unchacky)返回底层迭代器的方式。/cc@Yakk@sehe唉,它们没有包含std::function::target()
?懒汉的等价物。因为我还在开发程序的早期阶段,所以我想避免“绑定”类在一起。类型擦除似乎是一个好主意。稍后,当我有度量和分析器向我显示性能成本对于设计的好处来说太高时,它可能会消失,但现在,我想优先考虑好的设计而不是性能。@user1784377当然,除非很少有理由这样做对于非关联容器,除了<代码>向量
之外,还可以删除任何内容。这种删除可能会让您在以后要在同一向量中公开的内容旁边存储其他内容。但您应该记住的规则之一是“您可能不需要它”:编写一系列(可能成本高昂)早期的抽象可能会在一年内解决一些问题,但更可能的情况是,你不需要这种抽象。项目会死,可能会被过度抽象扼杀,或者抽象不需要。我确实知道“你可能不需要它”我倾向于在我真正需要它之前避免编写代码,但我想它也适用于设计和抽象。虽然我确实希望该项目在一年内仍然存在,我不希望以后再添加抽象,但我认为你可能是对的,现在去掉额外的抽象可能会简化和加速整个过程整体发展。