Designing an Iterator Wrapper

I wrote a class that wraps an iterator and returns converted values ​​on request:

// iterator-wrapper.h template<class Iter, class Val, class Fct> class IteratorWrapper { Iter cur_; const Iter last_; const Fct fct_; public: IteratorWrapper(Iter first, Iter last, const Fct fct) : cur_(first), last_(last), fct_(fct) {} const Val Value() const {return fct_(*cur_);} void Next() {++cur_;} bool Done() const {return cur_ == last_;} }; 

Now the class can use it to return iterators over some functions of its data:

 // mydata.h #include <map> #include "iterator-wrapper.h" class MyData { struct GetFirst { template<class T1, class T2> const T1& operator()(const std::pair<T1,T2>& aPair) const { return aPair.first; } }; struct GetSecond { template<class T1, class T2> const T2& operator()(const std::pair<T1,T2>& aPair) const { return aPair.second; } }; typedef std::string Key; typedef int Val; typedef std::map<Key, Val> Map; typedef Map::const_iterator MapIter; Map m_; public: typedef IteratorWrapper<MapIter, Key, GetFirst> KeysIter; typedef IteratorWrapper<MapIter, Val, GetSecond> ValuesIter; MyData() { // add some data m_["foo"] = 1; m_["bar"] = 2; } KeysIter GetKeys() const { return KeysIter(m_.begin(), m_.end(), GetFirst()); } ValuesIter GetValues() const { return ValuesIter(m_.begin(), m_.end(), GetSecond()); } }; 

And here is a usage example:

 #include <iostream> #include "iterator-wrapper-data.h" int main() { MyData d; std::cout << "KEYS:" << std::endl; MyData::KeysIter kit = d.GetKeys(); for(; !kit.Done(); kit.Next()){ std::cout << kit.Value() << std::endl; } std::cout << "VALUES:" << std::endl; MyData::ValuesIter vit = d.GetValues(); for(; !vit.Done(); vit.Next()){ std::cout << vit.Value() << std::endl; } return 0; } 

I have a few questions about this:

  • Is this a reasonable design, or can it be done more succinctly, perhaps using STL or boost? (I know there is boost::iterator_facade , but I found this code more complex than necessary, and I'm not sure if it does exactly what I want here.)

  • Why doesn't std::map contain something like this (I mean the keys() function, which returns an iterator over keys, etc.)? (Or that?)

  • What is wrong with returning a link, for example, const Val& Value() const (as opposed to returning by value, as in the first listing above)?

+4
source share
3 answers

You were on the right track by looking at boost :: iterator_facade, but you are even better off with boost :: transform_iterator .

+4
source

About your second question: the Boost RangeEx library ( zip file ) (not yet distributed with Boost, but accepted for future inclusion) contains a range of adapters for iterating over the keys and values ​​of the map:

 int main() { std::map<int, std::string> m; m[1] = "one"; m[2] = "two"; std::cout << "KEYS:" << std::endl; BOOST_FOREACH(int k, m | boost::adaptors::map_keys) { std::cout << k << std::endl; } std::cout << "VALUES:" << std::endl; BOOST_FOREACH(std::string const & v, m | boost::adaptors::map_values) { std::cout << v << std::endl; } return 0; } 
+2
source

This does not seem unreasonable to me, but I do not think that it is really necessary. There are select1st and select2nd, from the SGI STL Guide :

 int main() { map<int, double> M; M[1] = 0.3; M[47] = 0.8; M[33] = 0.1; transform(M.begin(), M.end(), ostream_iterator<int>(cout, " "), select1st<map<int, double>::value_type>()); // The output is 1 33 47. } 

Oh, and of course there is compose1 and compose2 when you want to do more than just send them to some insert or output an iterator directly.

+1
source

Source: https://habr.com/ru/post/1300561/


All Articles