Have you ever wanted to be able to iterate through your own class as if it was a cool STL container?
Do something like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyStorage : Storate<float> | |
{ | |
public: | |
... | |
}; | |
... | |
{ | |
... | |
for (auto& item : myStorageInstance) | |
{ | |
item.UpdateImportantInfo(); | |
} | |
... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyStorage : Storate<float> | |
{ | |
public: | |
... | |
class Iterator { | |
MyIterator(A::SomeClass* ptr) | |
{ | |
... | |
bool operator==(const Iterator& itr)... | |
bool operator!=(const Iterator& itr)... | |
Iterator operator++()... -- post-incr | |
Iterator operator++(int)... -- pre-incr | |
... | |
} | |
}; | |
Iterator begin(); | |
Iterator end(); | |
... | |
}; |
Here a code example. Simple one.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#include <iostream> | |
template <typename T> | |
class ListNode | |
{ | |
ListNode* _next = nullptr; | |
T _value; | |
public: | |
ListNode(T value) : _value(value) {} | |
void SetNext(ListNode* node) { | |
_next = node; | |
} | |
ListNode* GetNext() const { return _next; } | |
std::string GetValue() { | |
return _value; | |
} | |
class Iterator | |
{ | |
public: | |
Iterator(ListNode* ptr) : ptr_(ptr) { } | |
Iterator operator++() { Iterator i = *this; ptr_ = ptr_->GetNext(); return i; } | |
ListNode& operator*() { return *ptr_; } | |
ListNode* operator->() { return ptr_; } | |
bool operator==(const Iterator& rhs) { return ptr_ == rhs.ptr_; } | |
bool operator!=(const Iterator& rhs) { return ptr_ != rhs.ptr_; } | |
private: | |
ListNode* ptr_; | |
}; | |
Iterator begin() { return Iterator(this); } | |
Iterator end() { return Iterator(nullptr); } | |
}; | |
int main(int argc, char** argv) | |
{ | |
ListNode<std::string> node("I've"); | |
node.SetNext(new ListNode<std::string>("got the")); | |
node.GetNext()->SetNext(new ListNode<std::string>("power")); | |
for (auto itr : node) | |
std::cout << itr.GetValue() << " "; | |
std::cout << "\n"; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <algorithm> | |
#include <vector> | |
template <typename T> | |
using Storage = std::vector<T>; | |
class ValuesWrapper; | |
class BigBlobData | |
{ | |
friend ValuesWrapper; | |
Storage<int> _someValues; | |
Storage<float> _somePoints; | |
Storage<std::string> _someStrings; | |
public: | |
void SetPoints(Storage<float> someValues) { | |
std::merge(someValues.begin(), someValues.end(), | |
_someValues.begin(), _someValues.end(), | |
std::back_inserter(_someValues)); | |
} | |
}; | |
class ValuesWrapper { | |
const Storage<int>& _someValues; | |
public: | |
ValuesWrapper(const BigBlobData& blob) : _someValues(blob._someValues) | |
{ | |
} | |
class Iterator | |
{ | |
const int* _data; | |
public: | |
Iterator(const int* data) : _data(data) {} | |
Iterator operator++() | |
{ | |
_data++; | |
return {_data}; | |
} | |
bool operator==(const Iterator& rhs) | |
{ | |
return _data == rhs._data; | |
} | |
bool operator!=(const Iterator& rhs) | |
{ | |
return !(_data == rhs._data); | |
} | |
int operator*() | |
{ | |
return *_data; | |
} | |
}; | |
Iterator begin() { return Iterator(_someValues.data()); } | |
Iterator end() { return Iterator(_someValues.data() + _someValues.size()); } | |
}; | |
int main(int argc, char** argv) | |
{ | |
BigBlobData blob; | |
blob.SetPoints({1, 3, 4, 6, 7 , 8, 11, 13, 15, 16, 19, 20}); | |
blob.SetPoints({32, 34, 42, 53, 67, 71}); | |
for (int value : ValuesWrapper(blob)) | |
std::cout << value << " "; | |
std::cout << "\n"; | |
return 0; | |
} |
Iterators are neat concept separating STL algorithms and containers. Watching on Iterator pattern from another angle reveals different way to look at it's place in STL. Since Iterators usually implemented inside of containers they as glue connects two islands of the STL archipelago.
It's better to think about this relations as if there is a strictly established policy of data translation. Such high level of abstraction model let us see what the idea behind design of STL, as well as start to see other libraries on such level.
Iterate and prosper.