My question is a slight generalization of this one. For sake of discussion, I'll focus on iterating over the keys of a map. I would like to have a generic helper function, key_iterator
, that takes a map iterator and returns a map key iterator. For example, the following code:
#include "key_iterator.hpp"
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
int main(int argc, char** argv)
{
std::map<std::string, int> m;
m["One"] = 1;
m["Two"] = 2;
std::copy(key_iterator(m.begin()), key_iterator(m.end()), std::ostream_iterator<std::string>(std::cout, " "));
return 0;
}
should produce the following output:
One Two
As suggested in the solution to the question referred to above, boost::transform_iterator seems like an appropriate starting point for the implementation of key_iterator
. I have a half-way solution that looks like this for key_iterator.hpp:
#pragma once
#include <functional>
#include <map>
#include <boost/iterator/transform_iterator.hpp>
template <typename Key, typename Value>
class KeyGetter : public std::unary_function<std::pair<Key,Value>, Key>
{
public:
const Key& operator()(const std::pair<Key,Value>& p) const {return p.first;}
};
template<typename Key, typename Value>
boost::transform_iterator<KeyGetter<Key,Value>, typename std::map<Key,Value>::iterator>
key_iterator(typename std::map<Key,Value>::iterator itr)
{
return boost::make_transform_iterator<KeyGetter<Key,Value>, typename std::map<Key,Value>::iterator>(itr, KeyGetter<Key,Value>());
}
but with this implementation the Key and Value types are not being deduced automatically and I need to supply them manually to get it to compile:
std::copy(key_iterator<std::string,int>(m.begin()), key_iterator<std::string,int>(m.end()), std::ostream_iterator<std::string>(std::cout, " "));
Any thoughts on how to get this working the way I want?
Try this:
template <typename Iter>
struct KeyGetter : std::unary_function<typename Iter::value_type,
typename Iter::value_type::first_type>
{
const typename Iter::value_type::first_type& operator()
(const typename Iter::value_type& p) const
{ return p.first; }
};
template<typename Iter>
boost::transform_iterator<KeyGetter<Iter>, Iter> key_iterator(Iter itr)
{
return boost::make_transform_iterator<KeyGetter<Iter>, Iter>
(itr, KeyGetter<Iter>());
}
The idea being that the function at the call site should be templated directly on its argument, to avoid having to specify the template arguments explicitly.
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