C++ std::iterator without using std::vector or std::list internally
c++, iterator, stl
Solution
Is there some iterable class I can inherit from and override `++`, `==`, etc. to get the desired effect without storing the `std::vector<double>`?
Yes, there is. Its name is `std::iterator<std::input_iterator_tag, double>`.
Here is a start for you, using `int`. To save space in my brain, I use the same class to represent both the range and the iterator.
#include <iterator>
#include <iostream>
struct NumericRange : public std::iterator< std::input_iterator_tag, int >
{
int current, fini, delta;
typedef NumericRange iterator;
typedef iterator const_iterator;
iterator begin() { return *this; }
iterator end() { return iterator(fini, fini, delta); }
iterator& operator++() { current += delta; return *this; }
iterator operator++(int) { iterator result(*this); ++*this; return result; }
int operator*() const { return current; }
NumericRange(int start, int fini, int delta)
: current(start), fini(fini), delta(delta)
{
}
bool operator==(const iterator& rhs) {
return rhs.current == current;
}
bool operator!=(const iterator& rhs) {
return !(*this == rhs);
}
};
void f(int i, int j) {
std::cout << i << " " << j << "\n";
}
int main () {
int lower = 4, upper = 14, delta = 5;
NumericRange nr(lower, upper, delta);
for (NumericRange::const_iterator iter = nr.begin(); iter != nr.end(); iter++)
{
f(*iter, *nr.end());
}
}
Problem
I'm trying (as an exercise) to create a simple numeric range class in C++. It will let you iterate through evenly spaced doubles (like the numpy/Python `arange`): What I'd like to do (but with an iterator): ``` double lower = ..., upper = ..., delta = ...; for (double val = lower; val < upper; val += delta) { // do something with val f(val); } // include the last val to guarantee upper is included or exceeded f(val); // do something with val ``` Desired equivalent iterator code: ``` double lower = ..., upper = ..., delta = ...; NumericRange nr(lower, upper, delta); for (NumericRange::const_iterator iter = nr.begin(); iter != nr.end(); iter++) { f(*iter); } ``` I'd like my iterator to be compatible with STL iterators so I can reuse code (iterating through a NumericRange should be equivalent to iterating through std::vector). I've had success simply storing the values in a std::vector (and then using the std::vector's iterator). This is how everything I've found online has solved this problem. However, it really isn't necessary to store the entire list. Is there a way to avoid storing the entire set of values? Is there some `iterable` class I can inherit from and override `++`, `==`, etc. to get the desired effect without storing the `std::vector<double>`? (I'd really like to know how to do this without BOOST, even though it's great. I'm asking this because I'd like to learn how to write (from scratch) something like a BOOST solution. I definitely know that part of software engineering is using the tools created by others, but I really want to learn how those tools are designed and built.) My iterable NumericRange class (using `std::vector<double>` internally): ``` class NumericRange { protected: double lower, upper, delta; std::vector<double> sorted_range; public: typedef std::vector<double>::const_iterator const_iterator; NumericRange() { lower = upper = delta = std::numeric_limits<double>::quiet_NaN(); // vector is constructed empty } NumericRange(double lower_param, double upper_param, double delta_param) { lower = lower_param; upper = upper_param; delta = delta_param; assert(upper_param > lower_param); double val; // note: can be much faster without push_back for (val = lower_param; val < upper_param; val += delta_param) { sorted_range.push_back(val); } // ensure the upper_value is contained or surpassed sorted_range.push_back(val); } // to prevent comparison of the entire vector bool operator ==(const NumericRange & rhs) const { return lower == rhs.lower && upper == rhs.upper && delta == rhs.delta; } // note: this class doesn't really need to store the values in a // vector, but it makes the iterator interface much easier. const_iterator begin() const { return sorted_range.begin(); } const_iterator end() const { return sorted_range.end(); } double get_lower() const { return lower; } double get_upper() const { return upper; } double get_delta() const { return delta; } size_t size() const { return sorted_range.size(); } void print() const { std::cout << "[ " << lower << " : " << upper << ": +=" << delta << " ]" << std::endl; } }; ```