I've implemented a custom iterator based on the answer here:
https://stackoverflow.com/a/31886483/1973454
However, instead of the Type* _ptr
member, my code ultimately retrieves a value stored at some singular location, as if it were using the following function:
// my iterator class gets its values from this function
float globalFloat{ 0 };
float* retrieveFloat (int idx)
{
globalFloat = (float)idx;
return &globalFloat;
}
This means that in order for two iterators to be used simultaneously (i.e for searching using upper_bound), I've got to cache the float locally before allowing access:
class Iterator : public std::iterator<std::random_access_iterator_tag, float, int>
{
public:
Iterator () = default;
Iterator (int idx) : _index (idx) {}
Iterator& operator++ () noexcept { ++_index; return *this; }
Iterator& operator-- () noexcept { --_index; return *this; }
/// ... rest of iterator declaration
const float& operator* () const { _data = *retrieveFloat (_index); return _data; }
const float* operator-> () const { _data = *retrieveFloat (_index); return &this->_data; }
const float& operator[] (int offset) const { _data = *retrieveFloat (_index + offset); return _data; }
private:
int _index{ 0 };
mutable float _data{ 0 };
};
What I'm worried about is the last operator[]. According to cppreference:
https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator
the [] operator must return a reference type. However if I were to write the following code:
int main (int argc, char ** argv)
{
Iterator it;
if (it[0] == it[1])
return 0;
return 1;
}
Then I return 0 because each [] invocation modifies _data.
If I change how I'm subclassing std::iterator and use float as my "reference" type:
class Iterator : public std::iterator<std::random_access_iterator_tag, float, int, float*, float>
{
public:
/// ... rest of iterator declaration (constructors / operators)
const float operator* () const { _data = *retrieveFloat (_index); return _data; }
const float* operator-> () const { _data = *retrieveFloat (_index); return &this->_data; }
const float operator[] (int offset) const { _data = *retrieveFloat (_index + offset); return _data; }
};
then things work... but somehow that feels dirty. Is doing this kind of thing legal?
I know that if, instead of float, my data type was something heavier to copy then there would be a performance concern, but for argument's sake let's say that I'm only working with floats or lightweight PODs. Let's also assume I have no need of modifying the data being iterated over.
Thanks for any help you can provide, and sorry if I made this question too long. I can edit if need be.
- John