首页 > 解决方案 > 如何将具有 `next()` 方法的类似迭代器转换为常规的 `begin`/`end` 迭代器对?

问题描述

在我继承的代码库中,有一个看起来像迭代器的类(这不是确切的代码,但逻辑相似)。

template <class T>
struct IteratorLike {
    T* next() &; // either return a pointer to a valid value or nullptr
};

您使用它的方式与使用 Rust 迭代器的方式非常相似:

IteratorLike<...> it = ...;
while(auto* item = it.next()) {
    do_something(*item);
}

如何转换它以使其与基于 C++ 范围的 for 循环、算法或 range-v3 兼容?我使用的是 C++14(更准确地说是 gcc5.5),所以我不能有一个不同于迭代器本身类型的哨兵类型。


到目前为止,似乎最简单的方法是将迭代器和下一个值都存储在我的包装器中:


template <class T>
class MyIterator {
private:
    IteratorLike<T> m_iter;
    T* m_value;
public:
    using value_type = T;
    using difference_type = std::ptrdiff_t;
    using pointer = T*;
    using reference = T&; 
    using iterator_category = std::input_iterator_tag;

    reference operator*() const {
        assert(m_value && "trying to read past the end of the iterator");
        return *m_value;
    }   
    pointer operator->() {
        // I’m not sure the assert is needed here
        assert(m_value && "trying to read past the end of the iterator");
        return m_value;
    }   

    // Prefix increment
    MyIterator& operator++() {
        m_value = m_iter.next();
        return *this;
    }   

    // Postfix increment
    MyIterator operator++(int) {
        MyIterator tmp = *this;
        ++(*this);
        return tmp;
    }
    
    // used by `my_collection.begin()`
    explicit MyIterator(IteratorLike<T> iter)
        : m_iter{m_iter}
        , m_value{this->self.next()}
    {}  
    // missing operator == and operator != as well as the constructor
    // used `my_collection.end()
};

但是,我不明白my_collection.end()应该返回什么(编辑:我只是检查,我不能 default-initialize m_iter),也不知道如何拥有有意义的比较运算符。

注意:我基本上是在尝试与this完全相反。

标签: c++iterator

解决方案


由于IteratorLike不可default构造,但显然是可复制构造的,因此您也可以使用必须构造end()迭代器的实例。例子:

// used by `my_collection.begin()`
explicit MyIterator(const IteratorLike<T>& iter) :
    m_iter{iter},
    m_value{m_iter.next()}
{}

// used by `my_collection.end()`
MyIterator(const IteratorLike<T>& iter, std::nullptr_t) :
    m_iter{iter},
    m_value{nullptr}
{}

bool operator!=(const MyIterator& rhs) const {
    return m_value != rhs.m_value;
}

然后在my_collection

template<typename T>
class my_collection {
public:
    MyIterator<T> begin() { return MyIterator<T>{itlike}; }
    MyIterator<T> end() { return {itlike, nullptr}; }

private:    
    IteratorLike<T> itlike;
};

推荐阅读