So, say, I have a class that has std::list<std::pair<int, std::string>>
inside of it; how can I implement an iterator for this class such that it iterates over strings contained in this list?
Or, for example, in my class I have a vector of struct
s with fields a
, b
and c
; can I create an iterator (maybe inherit vector's iterator? don't know), which, when dereferenced, will return a std::pair
, corresponding to (b, c)
?
By iterator I mean something like std::vector
's iterators: something, that I can get via whatever.begin()
and iterate over, as mentioned, strings inside the list.
UPD Okay, here's more info on what I want. In my HashMap
class I have items
: a list of structs
: each with a key, a value and a pointer to it's place in the table. What I need is an iterator; but not the one that I can get by doing items.begin()
, since this iterator, when dereferenced, will return my struct. I need an iterator, such that I can return it when user calls HashMap.begin()
, and it should dereference into a std::pair
, corresponding to (key, value).
This should, hopefully, make my question clearer.
UPD2
Here is my struct
, if that helps:
template<class KeyType, class ValueType>
struct node {
KeyType key;
ValueType value;
node** place;
node(KeyType key_ = KeyType(), ValueType value_ = ValueType()): key(key_), value(value_) {};
};
One elegant way is to use transforming iterators or a transformed range:
#include <iostream>
#include <list>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/iterator/transform_iterator.hpp>
int main() {
std::list<std::pair<int, std::string>> l;
auto extractor = [](auto&& elem) { return elem.second; };
// Using a transformed range.
for(auto&& v: l | boost::adaptors::transformed(extractor))
std::cout << v << '\n';
// Using transform iterators.
for(auto i = boost::make_transform_iterator(l.begin(), extractor), j = boost::make_transform_iterator(l.end(), extractor); i != j; ++i)
std::cout << *i << '\n';
}
To use a transform iterator for you containers you can do something like:
struct MyContianer
{
std::list<std::pair<int, std::string>> container;
static auto constexpr first_extractor = [](auto&& elem) { return elem.second; };
using iterator_first = decltype(boost::make_transform_iterator(container.begin(), first_extractor));
iterator_first begin_first() { return {container.begin(), first_extractor}; }
iterator_first end_first() { return {container.end(), first_extractor}; }
static auto constexpr second_extractor = [](auto&& elem) { return elem.second; };
using iterator_second = decltype(boost::make_transform_iterator(container.begin(), second_extractor));
iterator_second begin_second() { return {container.begin(), second_extractor}; }
iterator_second end_second() { return {container.end(), second_extractor}; }
};
decltype(MyContianer::first_extractor) constexpr MyContianer::first_extractor;
decltype(MyContianer::second_extractor) constexpr MyContianer::second_extractor;
int main() {
MyContianer c;
c.begin_first();
c.begin_second();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With