Задача простая: реализовать range-based итератор для произвольной структуры. При этом он должен быть как можно проще и содержать строго необходимые методы.
Что получилось (вектор просто для примера):
#include <vector>
#include <iostream>
class Range
{
private:
class Impl
{
public:
using value_type = int;
using const_reference = const int&;
Impl(const size_t v, const std::vector<int> &values) : m_idx(v), m_values(values) {}
const_reference operator*() const { return m_values[m_idx]; }
Impl& operator++()
{
m_idx++;
return *this;
}
bool operator!=(const Impl& rhs) { return m_idx != rhs.m_idx; }
private:
// Тут может быть что угодно.
size_t m_idx;
const std::vector<int> &m_values;
};
public:
Range(const std::vector<int> &values) : m_values(values) {}
typedef Impl iterator;
iterator begin() const { return Impl(0, m_values); }
iterator end() const { return Impl(m_values.size(), m_values); }
private:
// Тут может быть что угодно.
const std::vector<int> &m_values;
};
int main(int argc, char *argv[])
{
const std::vector<int> values = { 1, 2, 3, 4 };
for (const int &v : Range(values))
{
std::cout << v << std::endl;
}
return 0;
}
Вопросы:
- Что можно убрать? Что лишнее?
- Что нужно добавить, чтобы даже самые злые линтеры не возмущались?
По факту, 90% кода - мусор. Всё что нужно, это своя реализация T& operator++()
.
То есть хотелось бы получить возможность использовать подход rust'a, где мне нужно реализовать только метод next():
struct Range<'a> {
idx: usize,
values: &'a Vec<i32>,
}
impl<'a> Range<'a> {
fn new(values: &'a Vec<i32>) -> Self {
Range {
idx: 0,
values,
}
}
}
impl<'a> Iterator for Range<'a> {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if self.idx == self.values.len() {
return None;
}
self.idx += 1;
Some(self.values[self.idx - 1])
}
}
fn main() {
let values = vec![1, 2, 3, 4];
for v in Range::new(&values) {
println!("{}", v);
}
}