如何将具有 `next()` 方法的类迭代器转换为常规的 `begin`/`end` 迭代器对?
How to convert an iterator-like that has a `next()` methode to a regular `begin`/`end` iterator pair?
在我继承的代码库中,有一个看起来像迭代器的class(这不是确切的代码,但逻辑是相似的)。
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()
应该 return 是什么(编辑:我只是检查一下,我不能默认初始化 m_iter
),也不明白如何进行有意义的比较运营商。
注意:我基本上是在尝试完全相反 this。
因为 IteratorLike
不是 default
可构造的,但显然 copy 是可构造的,你可以使用你必须构造你的 [=14] 的实例=] 也是迭代器。示例:
// 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;
};
在我继承的代码库中,有一个看起来像迭代器的class(这不是确切的代码,但逻辑是相似的)。
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()
应该 return 是什么(编辑:我只是检查一下,我不能默认初始化 m_iter
),也不明白如何进行有意义的比较运营商。
注意:我基本上是在尝试完全相反 this。
因为 IteratorLike
不是 default
可构造的,但显然 copy 是可构造的,你可以使用你必须构造你的 [=14] 的实例=] 也是迭代器。示例:
// 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;
};