Boost logo

Boost Users :

From: Alan M. Carroll (amc_at_[hidden])
Date: 2008-06-23 22:30:07


At 11:06 AM 6/21/2008, you wrote:
Hi,

This is probably a very newbie question. I'd like to iterate through the values of a std::map. I searched through the archives, and found this thread on this mailing list about it:

http://lists.boost.org/boost-users/2007/11/32374.php

Unfortunately I can't put the partial recommendations together from that thread to work for me. While this is most probably due to my lack of experience with boost, can someone point to a sort-of complete usage solution to this question? Would be really appreciated.

Here are two solutions in one. One does the transform_iterator by hand, the other uses a helper class ("make_view") based on transform_iterator and iterator_range, included at the end. "make_view" is based on a suggestion that was on the list a while back. The former does not use boost::bind because the type must be passed to transform_iterator and I haven't the energy to figure out what that type is. If you're hand rolling this for a specific std::map, don't need the generality, and want to hand iterators back to your client, it is (IMHO) better to do it with an explitic function (or static method). "make_view" is what I use when I want something generic.

# include <map>
# include <boost/foreach.hpp>
# include <iostream>
# include <boost/bind.hpp>
# include <boost/iterator/transform_iterator.hpp>
# include <local/make_view.hpp>

typedef std::map<int, std::string> Map;
std::string const& MapValue(Map::value_type const& v) { return v.second; }
typedef boost::transform_iterator<std::string const& (*)(Map::value_type const&), Map::const_iterator> value_iterator;

int main(int argc, char* argv[])
{
    Map map;
    map.insert(Map::value_type(1, "one"));
    map.insert(Map::value_type(2, "two"));
    map.insert(Map::value_type(3, "three"));

    // Simple, but requires iteration over the entire container
    BOOST_FOREACH(std::string const& s, boost::make_view(map, bind(&Map::value_type::second, _1)))
        std::cout << s << " , ";
    std::cout << std::endl;

    // More flexible iterators, but need more support
    value_iterator spot(map.begin(), &MapValue);
    value_iterator limit(map.end(), &MapValue);
    while (spot != limit) {
        std::cout << *spot << " , ";
        ++spot;
    }
    return 0;
}

local/make_view.hpp

# pragma once
/** @file
    Create a transformed view of a range or a container.
 */

# include <boost/iterator/transform_iterator.hpp>
# include <boost/range/iterator_range.hpp>
# include <boost/range/begin.hpp>
# include <boost/range/end.hpp>
# include <boost/range/iterator.hpp>

/// Boost namespace
namespace boost {

/** Create a transform view from an iterator pair.
    A view is a lazy reference to a sequence, specified here by @a begin and @a end.
    The values in the sequence are transformed on access by @a transform. This avoids
    the expense of allocating a container to hold the intermediate results.
    @return The iterator range.
 */
template
    < typename I ///< Iterator type
    , typename F ///< Functor type
    >
inline iterator_range<transform_iterator< F, I > > make_view
    ( I
const & begin        ///< Start of source range
    , I const & end          ///< End of source range
    , F const & transform    ///< Transform functor
    )
{
   
return make_iterator_range(
        make_transform_iterator(begin, transform),
        make_transform_iterator(end, transform));
}

/** Create a view from an iterator range.
    A view is a lazy reference to a sequence, specified here by @a begin and @a end.
    The values in the sequence are transformed on access by @a transform. This avoids
    the expense of allocating a container to hold the intermediate results.
    @note @a range can be an STL compliant container, in addition to a Boost iterator range.
    @return The new iterator range.

    @internal Note that we only support const containers, because being a view
    there's no good way to map any changes back to the original container.

    @internal Boost 1.34.1 requires the use of range_const_iterator<RANGE>, but
    1.35.0 permits the use of range_iterator<RANGE const>.
 */
template
    < typename RANGE ///< Range type
    , typename F     ///< Transform functor type
    >
inline iterator_range< transform_iterator< F, typename range_const_iterator< RANGE >::type > > make_view
    ( RANGE
const & range ///< Source range
    , F const & transform ///< Transform functor
    )
{
   
return make_view(begin(range), end(range), transform);
}

}
// namespace boost

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net