如何将具有 `next()` 方法的类似迭代器转换为普通的 `begin`/`end` 迭代器对?

3

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

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++范围-based 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()应该返回什么(编辑:我刚刚检查了一下,我不能默认初始化m_iter),也不知道如何编写有意义的比较运算符。 注意:基本上,我正在尝试完全相反于这个例子

3
听起来在这种情况下,“end”迭代器是一个内部指针值为“nullptr”的迭代器。 - François Andrieux
1
我曾经处理过这样的代码库,它非常令人头痛。如果你想获取序列的末尾,你不应该使用 my_collection.end()。相反,你应该使用空构造的迭代器(类似于流迭代器),在你的 != 运算符中,如果一个迭代器是默认构造的,另一个迭代器返回的指针为 nullptr,则认为两个迭代器相等。 - SergeyA
听起来在这种情况下,一个结束迭代器是一个具有空指针内部指针值的迭代器。是的,但我应该使用什么值来替换 m_iter?编辑:我刚刚双重检查了,IteratorLike 不是默认可构造的。 - Robin
使用 std::optional<IteratorLike<T>>(或 boost::optional)。 - Chris Dodd
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
1

由于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;
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,