Monday, October 21, 2013

How to iterate over the values of a std::map

EDIT: Changed example to better reflect the generality of the problem = title of this post. END EDIT.

Now that C++ has lambdas, the C++ STL algorithms are practically useful, but how do you iterate over the values of a std::map?

Say you have a function template:

template<typename Iter>void f(Iter curr, Iter end);

f assumes the iterators point to std::strings:

std::vector<std::string> v;

f(v.begin(),v.end()); // ok

std::map<int,std::string> m;

f(m.begin(),m.end());// Won't work: *m.begin() is a pair<Key,Value>

What we thus need is a way of converting the map::iterator (and map::const_iterator) to an iterator to always dereferences the Value type of the pair.

Solution using Boost

The solution is easy using boost:

#define BOOST_RESULT_OF_USE_DECLTYPE#include <boost/iterator/transform_iterator.hpp>// First, define a lambda to get the second element of a pair:auto get_second =[](conststd::pair<constint,std::string>& p){return p.second;};// Then, we can convert a map iterator into an iterator that automatically dereferences the second elementauto beg = boost::make_transform_iterator(m.begin(),get_second);auto end = boost::make_transform_iterator(m.end(),get_second);

f(beg,end); // ok, works!

The line

#define BOOST_RESULT_OF_USE_DECLTYPE

is needed so inform the boost libraries that the result type (Value in this case) should be inferred using decltype(), rather than by requiring a result_of typedef (prior to C++11, decltype did not exist).

Solution without Boost

If you can't use boost, you'll need to implement the dereferencing by hand. Here's the code: