5

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?

4
  • Similar question: stackoverflow.com/questions/110157/… Commented Aug 17, 2011 at 2:17
  • What's wrong with map_keys from boost.range? boost.org/doc/libs/release/libs/range/doc/html/range/reference/… Commented Aug 17, 2011 at 2:24
  • @dnikku - Thanks there are some good suggestions there, but none that quite do what I'd like key_iterator to do, namely, return a map "key iterator" given a map "iterator". Commented Aug 17, 2011 at 2:30
  • @Cubbi - Thanks! I wasn't aware of map_keys. I am still interested in seeing how to modify my function template to provide automatic deduction of the template args, though. Commented Aug 17, 2011 at 2:42

1 Answer 1

7

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.