You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在同一变量中存储不同范围操作的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 12:59:51