如何在同一变量中存储不同范围操作的CustomIterator实例?
解决不同类型CustomIterator实例的统一存储问题
核心结论
C++20的std::ranges::filter_view、std::ranges::reverse_view等视图类没有公共基类,它们都是独立的模板特化类型,无法直接通过视图的继承关系来统一CustomIterator的类型。要实现不同CustomIterator实例的灵活存储,有两种可靠方案:
方案一:抽象基类+多态
为所有CustomIterator特化版本定义一个抽象基类,包含迭代器的核心操作接口,让CustomIterator继承并实现这些接口,最后通过基类指针/智能指针来存储不同实例。
示例代码
#include <ranges> #include <vector> #include <memory> #include <iostream> // 抽象基类:定义迭代器的公共操作接口 class CustomIteratorBase { public: virtual ~CustomIteratorBase() = default; virtual void increment() = 0; // 对应 operator++ virtual int& dereference() = 0; // 对应 operator* virtual bool equals(const CustomIteratorBase& other) const = 0; // 对应 operator== }; // 模板迭代器类:继承抽象基类 template <std::ranges::range Container> class CustomIterator : public CustomIteratorBase { private: using IterType = typename Container::iterator; IterType current_; public: explicit CustomIterator(Container& range) : current_(range.begin()) {} // 实现基类的虚函数 void increment() override { ++current_; } int& dereference() override { return *current_; } bool equals(const CustomIteratorBase& other) const override { // 动态转换到对应特化类型,比较底层迭代器 const auto* typed_other = dynamic_cast<const CustomIterator*>(&other); return typed_other && (current_ == typed_other->current_); } // 保留模板版本的运算符,方便直接使用 CustomIterator& operator++() { ++current_; return *this; } int& operator*() { return *current_; } bool operator==(const CustomIterator& other) const { return current_ == other.current_; } }; // 使用示例 int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; auto filter_view = vec | std::views::filter([](int x) { return x % 2 == 0; }); auto reverse_view = vec | std::views::reverse; // 用智能指针存储不同类型的CustomIterator std::unique_ptr<CustomIteratorBase> iter1 = std::make_unique<CustomIterator<decltype(filter_view)>>(filter_view); std::unique_ptr<CustomIteratorBase> iter2 = std::make_unique<CustomIterator<decltype(reverse_view)>>(reverse_view); // 通过基类接口操作迭代器 iter1->increment(); std::cout << iter1->dereference() << "\n"; // 输出4 iter2->increment(); std::cout << iter2->dereference() << "\n"; // 输出4 return 0; }
注意事项
- 基类的接口需要根据迭代器的类别(输入/正向/双向等)扩展,比如双向迭代器需要添加
decrement()虚函数。 - 如果迭代器指向的元素类型不固定,可以将
dereference()的返回值改为std::any,使用时再动态转换,但会带来一定的性能开销。
方案二:类型擦除包装器
实现一个类型擦除的包装类,封装不同CustomIterator特化版本的操作,对外提供统一的迭代器接口,无需手动管理指针。
示例代码
#include <ranges> #include <vector> #include <memory> #include <iostream> template <std::ranges::range Container> class CustomIterator { private: using IterType = typename Container::iterator; IterType current_; public: explicit CustomIterator(Container& range) : current_(range.begin()) {} CustomIterator& operator++() { ++current_; return *this; } int& operator*() { return *current_; } bool operator==(const CustomIterator& other) const { return current_ == other.current_; } }; // 类型擦除的迭代器包装类 class AnyCustomIterator { private: // 概念类:定义核心操作接口 struct Concept { virtual ~Concept() = default; virtual void increment() = 0; virtual int& dereference() = 0; virtual bool equals(const Concept* other) const = 0; virtual std::unique_ptr<Concept> clone() const = 0; }; // 模型类:适配具体的CustomIterator特化版本 template <std::ranges::range Container> struct Model : Concept { CustomIterator<Container> iter; explicit Model(CustomIterator<Container> i) : iter(std::move(i)) {} void increment() override { ++iter; } int& dereference() override { return *iter; } bool equals(const Concept* other) const override { if (const auto* m = dynamic_cast<const Model*>(other)) { return iter == m->iter; } return false; } std::unique_ptr<Concept> clone() const override { return std::make_unique<Model>(iter); } }; std::unique_ptr<Concept> ptr_; public: // 构造函数:接受任意CustomIterator特化版本 template <std::ranges::range Container> AnyCustomIterator(CustomIterator<Container> iter) : ptr_(std::make_unique<Model<Container>>(std::move(iter))) {} // 拷贝构造/赋值:需要克隆内部模型 AnyCustomIterator(const AnyCustomIterator& other) : ptr_(other.ptr_ ? other.ptr_->clone() : nullptr) {} AnyCustomIterator& operator=(const AnyCustomIterator& other) { if (this != &other) { ptr_ = other.ptr_ ? other.ptr_->clone() : nullptr; } return *this; } // 移动构造/赋值:默认实现即可 AnyCustomIterator(AnyCustomIterator&&) = default; AnyCustomIterator& operator=(AnyCustomIterator&&) = default; // 对外暴露的迭代器运算符 AnyCustomIterator& operator++() { ptr_->increment(); return *this; } int& operator*() { return ptr_->dereference(); } bool operator==(const AnyCustomIterator& other) const { if (!ptr_ || !other.ptr_) { return !ptr_ && !other.ptr_; } return ptr_->equals(other.ptr_.get()); } }; // 使用示例 int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; auto filter_view = vec | std::views::filter([](int x) { return x % 2 == 0; }); auto reverse_view = vec | std::views::reverse; // 直接用包装类存储不同类型的CustomIterator AnyCustomIterator iter1(CustomIterator<decltype(filter_view)>(filter_view)); AnyCustomIterator iter2(CustomIterator<decltype(reverse_view)>(reverse_view)); // 像普通迭代器一样使用 ++iter1; std::cout << *iter1 << "\n"; // 输出4 ++iter2; std::cout << *iter2 << "\n"; // 输出4 return 0; }
优势
- 使用方式和普通迭代器完全一致,无需手动管理智能指针。
- 内部封装了类型擦除逻辑,对外隐藏了模板特化的细节。
内容的提问来源于stack exchange,提问作者yonutix
相关产品推荐
相关产品推荐

