copy map to a list

Discussion in 'C++' started by sks_cpp, Jul 8, 2003.

  1. sks_cpp

    sks_cpp Guest

    map<int, Drive*> dMap;
    list<Drive*> dList;

    copy( dMap.begin(), dMap.end(), back_inserter(dList) ); // incorrect

    The above will not because value_type of dMap is different than dList.
    Now, I would like to wrap the map iterators inside a class class (let's call
    it WrapMap)

    WrapMap wm(dMap.begin(), dMap.end() );

    Now,
    copy( wm.begin(), wm.end(), back_inserter(dList) ); // this should work

    This means that operator* and operator++ need to be implemented for
    "iterator" that is associated with WrapMap. Of course, begin and end should
    return the associated WrapMap iterator.

    Am I heading in the right direction here? I would like to generalize this
    wrapper, iterator, and const_iterator eventually - does anyone have any
    ideas?

    Thanks.
     
    sks_cpp, Jul 8, 2003
    #1
    1. Advertising

  2. "sks_cpp" <> wrote in message
    news:N8rOa.523050$...
    | map<int, Drive*> dMap;
    | list<Drive*> dList;
    |
    | copy( dMap.begin(), dMap.end(), back_inserter(dList) ); // incorrect
    ....
    | Am I heading in the right direction here? I would like to generalize this
    | wrapper, iterator, and const_iterator eventually - does anyone have any
    | ideas?

    The more general approach is to wrap the iterator only,
    so that it returns member 'second' of the value when
    it is being dereferenced.

    This can be done from scratch with code like this:

    // Iterator wrapper which returns member 'second'
    // of a value when being dereferenced.
    template<typename I>
    class IterTo2nd
    {
    public:
    typedef IterTo2nd<I> DSelf; // shortcut for type of *this

    // required typedefs within each iterator
    typedef I::iterator_category iterator_category;
    typedef I::value_type::second_type value_type;
    typedef I::distance_type distance_type;

    // constructor to create from the wrapped iterator
    explicit IterTo2nd(I i) : i_(i) {}

    // That's the actual work done: return 'second' member
    value_type& operator* () const { return (*i_).second; }
    value_type* operator->() const { return &(*i_).second; }

    // boilerplate code to forward other iterator ops
    DSelf& operator++() { ++i_; return *this; }
    DSelf operator++(int) { DSelf ans(*this); ++i_; return ans; }
    friend bool operator==( DSelf const& a, DSelf const& b )
    { return a.i_ == b.i_; }
    friend bool operator!=( DSelf const& a, DSelf const& b )
    { return a.i_ != b.i_; }
    // etc for other operators: < > <= >= ...
    private:
    I i_;
    };

    // helper function to create instances of IterTo2nd
    template<typename I>
    IterTo2nd<I> iterTo2nd(I const& i)
    { return IterTo2nd<I>(i); }


    You can then write:
    copy( iterTo2nd(dMap.begin()), iterTo2nd(dMap.end())
    , back_inserter(dList) ); // now correct


    Note that the iterator library of www.boost.org has some
    helper classes to help avoid writing all the boilerplate
    code for each iterator.


    hth,
    --
    Ivan Vecerina, Dr. med. <> http://www.post1.com/~ivec
    Brainbench MVP for C++ <> http://www.brainbench.com
     
    Ivan Vecerina, Jul 8, 2003
    #2
    1. Advertising

  3. "sks_cpp" <> wrote in message news:<N8rOa.523050$>...

    > map<int, Drive*> dMap;
    > list<Drive*> dList;
    >
    > copy( dMap.begin(), dMap.end(), back_inserter(dList) ); // incorrect
    >
    > The above will not because value_type of dMap is different than dList.


    You just picked the wrong algorithm -- try std::transform instead. Use
    a predicate which returns the relevant field (.second in this case) of
    each pair in the map, and std::transform will insert them into the
    list for you. For instance:

    #include <functional>

    struct get_second
    : std::unary_function<std::map<int, Drive *>::value_type,
    Drive *> {
    result_type operator() (argument_type p) const {
    return p.second;
    }
    };

    void xform (const std::map<int, Drive*> &dMap,
    std::list<Drive*> &dList) {
    std::transform(dMap.begin(), dMap.end(),
    std::back_inserter(dList), get_second());
    }

    In my code, I might use boost::bind from Boost.org instead of that
    custom get_second struct, like so:

    #include <boost/bind.hpp>

    void xform (const std::map<int, Drive*> &dMap,
    std::list<Drive*> &dList) {
    typedef std::map<int, Drive*>::value_type pair_type;
    std::transform(dMap.begin(), dMap.end(),
    std::back_inserter(dList),
    boost::bind(&pair_type::second, _1));
    }

    > Now, I would like to wrap the map iterators inside a class class (let's call
    > it WrapMap)
    >
    > WrapMap wm(dMap.begin(), dMap.end() );
    >
    > Now,
    > copy( wm.begin(), wm.end(), back_inserter(dList) ); // this should work
    >
    > This means that operator* and operator++ need to be implemented for
    > "iterator" that is associated with WrapMap. Of course, begin and end should
    > return the associated WrapMap iterator.
    >
    > Am I heading in the right direction here?


    First, if the std::transform stuff above works for you, you probably
    should use that instead. Second, if you really do want to wrap the
    iterators, then just wrap the iterators, not the whole map. Third,
    this has already been done, again by the Boost.org people:

    #include <boost/iterator_adaptors.hpp>
    // using get_second as defined above

    void xform (const std::map<int, Drive*> &dMap,
    std::list<Drive*> &dList) {
    get_second gs;
    std::copy(boost::make_transform_iterator(dMap.begin(), gs),
    boost::make_transform_iterator(dMap.end(), gs),
    std::back_inserter(dList));
    }

    Oddly enough, the transform iterator adapter doesn't work with
    boost::bind and a pointer-to-member as I did at the top -- "forming
    pointer to reference." Grr.

    - Shane
     
    Shane Beasley, Jul 8, 2003
    #3
  4. sks_cpp

    Guest

    "sks_cpp" <> wrote in message news:<N8rOa.523050$>...
    > map<int, Drive*> dMap;
    > list<Drive*> dList;
    >
    > copy( dMap.begin(), dMap.end(), back_inserter(dList) ); // incorrect
    >
    > The above will not because value_type of dMap is different than dList.
    > Now, I would like to wrap the map iterators inside a class class (let's call
    > it WrapMap)
    >
    > WrapMap wm(dMap.begin(), dMap.end() );
    >
    > Now,
    > copy( wm.begin(), wm.end(), back_inserter(dList) ); // this should work
    >
    > This means that operator* and operator++ need to be implemented for
    > "iterator" that is associated with WrapMap. Of course, begin and end should
    > return the associated WrapMap iterator.
    >
    > Am I heading in the right direction here? I would like to generalize this
    > wrapper, iterator, and const_iterator eventually - does anyone have any
    > ideas?
    >
    > Thanks.


    I think you need iterator adaptor which will iterate over value types
    of map.
    Something like:

    /******************************************************************/
    template <class _MapIter>
    struct _value_iter : public _MapIter {
    typedef typename _MapIter::value_type::second_type value_type;

    typedef typename Loki::Select<
    Loki::TypeTraits<typename _MapIter::reference>::isConst,
    const typename _MapIter::value_type::second_type&,
    typename _MapIter::value_type::second_type&
    >::Result reference;


    typedef typename Loki::Select<
    Loki::TypeTraits<typename _MapIter::pointer>::isConst,
    const typename _MapIter::value_type::second_type*,
    typename _MapIter::value_type::second_type*
    >::Result pointer;


    _value_iter() {}
    _value_iter(const _MapIter& it) : _MapIter(it) {}
    reference operator*() const {
    return _MapIter::eek:perator*().second;
    }
    pointer operator->() const {
    return &**this;
    }
    };

    template <class _MapIter>
    inline _value_iter<_MapIter> value_iter(const _MapIter& it) {
    return _value_iter<_MapIter>(it);
    }
    /******************************************************************/

    Usage:
    copy(value_iter(dMap.begin()), value_iter(dMap.end()),
    back_inserter(dList) ); // now correct

    Notice that I used Loki only to distinguish between const and nonconst
    iterators.

    There is probably better solution somewhere in boost lib.

    Regards
     
    , Jul 8, 2003
    #4
  5. sks_cpp

    sks_cpp Guest

    > "sks_cpp" <> wrote in message
    news:<N8rOa.523050$>...
    > > map<int, Drive*> dMap;
    > > list<Drive*> dList;
    > >
    > > copy( dMap.begin(), dMap.end(), back_inserter(dList) ); // incorrect
    > >
    > > The above will not because value_type of dMap is different than dList.
    > > Now, I would like to wrap the map iterators inside a class class (let's

    call
    > > it WrapMap)
    > >
    > > WrapMap wm(dMap.begin(), dMap.end() );
    > >
    > > Now,
    > > copy( wm.begin(), wm.end(), back_inserter(dList) ); // this should work
    > >
    > > This means that operator* and operator++ need to be implemented for
    > > "iterator" that is associated with WrapMap. Of course, begin and end

    should
    > > return the associated WrapMap iterator.
    > >
    > > Am I heading in the right direction here? I would like to generalize

    this
    > > wrapper, iterator, and const_iterator eventually - does anyone have any
    > > ideas?
    > >
    > > Thanks.

    >
    > I think you need iterator adaptor which will iterate over value types
    > of map.
    > Something like:
    >
    > /******************************************************************/
    > template <class _MapIter>
    > struct _value_iter : public _MapIter {
    > typedef typename _MapIter::value_type::second_type value_type;
    >
    > typedef typename Loki::Select<
    > Loki::TypeTraits<typename _MapIter::reference>::isConst,
    > const typename _MapIter::value_type::second_type&,
    > typename _MapIter::value_type::second_type&
    > >::Result reference;

    >
    > typedef typename Loki::Select<
    > Loki::TypeTraits<typename _MapIter::pointer>::isConst,
    > const typename _MapIter::value_type::second_type*,
    > typename _MapIter::value_type::second_type*
    > >::Result pointer;

    >
    > _value_iter() {}
    > _value_iter(const _MapIter& it) : _MapIter(it) {}
    > reference operator*() const {
    > return _MapIter::eek:perator*().second;
    > }
    > pointer operator->() const {
    > return &**this;
    > }
    > };
    >
    > template <class _MapIter>
    > inline _value_iter<_MapIter> value_iter(const _MapIter& it) {
    > return _value_iter<_MapIter>(it);
    > }
    > /******************************************************************/
    >
    > Usage:
    > copy(value_iter(dMap.begin()), value_iter(dMap.end()),
    > back_inserter(dList) ); // now correct
    >
    > Notice that I used Loki only to distinguish between const and nonconst
    > iterators.
    >
    > There is probably better solution somewhere in boost lib.
    >
    > Regards


    What is "Loki"? - is that some library that I am not aware of? I see that
    you inherit the map's iterator - I thought about doing this but hell, I
    would have never come up with the code that you did above. Now, can you
    generalize this to give back to you either first or second - can you make
    that a compile-time code generation parameter somehow?
     
    sks_cpp, Jul 9, 2003
    #5
  6. sks_cpp

    sks_cpp Guest

    "Ivan Vecerina" <> wrote in message
    news:...
    > "sks_cpp" <> wrote in message
    > news:N8rOa.523050$...
    > | map<int, Drive*> dMap;
    > | list<Drive*> dList;
    > |
    > | copy( dMap.begin(), dMap.end(), back_inserter(dList) ); // incorrect
    > ...
    > | Am I heading in the right direction here? I would like to generalize

    this
    > | wrapper, iterator, and const_iterator eventually - does anyone have any
    > | ideas?
    >
    > The more general approach is to wrap the iterator only,
    > so that it returns member 'second' of the value when
    > it is being dereferenced.
    >
    > This can be done from scratch with code like this:
    >
    > // Iterator wrapper which returns member 'second'
    > // of a value when being dereferenced.
    > template<typename I>
    > class IterTo2nd
    > {
    > public:
    > typedef IterTo2nd<I> DSelf; // shortcut for type of *this
    >
    > // required typedefs within each iterator
    > typedef I::iterator_category iterator_category;
    > typedef I::value_type::second_type value_type;
    > typedef I::distance_type distance_type;
    >
    > // constructor to create from the wrapped iterator
    > explicit IterTo2nd(I i) : i_(i) {}
    >
    > // That's the actual work done: return 'second' member
    > value_type& operator* () const { return (*i_).second; }
    > value_type* operator->() const { return &(*i_).second; }
    >
    > // boilerplate code to forward other iterator ops
    > DSelf& operator++() { ++i_; return *this; }
    > DSelf operator++(int) { DSelf ans(*this); ++i_; return ans; }
    > friend bool operator==( DSelf const& a, DSelf const& b )
    > { return a.i_ == b.i_; }
    > friend bool operator!=( DSelf const& a, DSelf const& b )
    > { return a.i_ != b.i_; }
    > // etc for other operators: < > <= >= ...
    > private:
    > I i_;
    > };
    >
    > // helper function to create instances of IterTo2nd
    > template<typename I>
    > IterTo2nd<I> iterTo2nd(I const& i)
    > { return IterTo2nd<I>(i); }
    >
    >
    > You can then write:
    > copy( iterTo2nd(dMap.begin()), iterTo2nd(dMap.end())
    > , back_inserter(dList) ); // now correct
    >
    >
    > Note that the iterator library of www.boost.org has some
    > helper classes to help avoid writing all the boilerplate
    > code for each iterator.


    Now, the boost code is public domain; to use freely or do you have to buy
    (install) their libraries? I did look at their code but that is way out
    there. I am not a beginner c++ programmer but templates are another thing
    and then you have iterators in combination with templates... Anyway thanks
    for your help.
     
    sks_cpp, Jul 9, 2003
    #6
  7. sks_cpp

    sks_cpp Guest

    "Shane Beasley" <> wrote in message
    news:...
    > "sks_cpp" <> wrote in message

    news:<N8rOa.523050$>...
    >
    > > map<int, Drive*> dMap;
    > > list<Drive*> dList;
    > >
    > > copy( dMap.begin(), dMap.end(), back_inserter(dList) ); // incorrect
    > >
    > > The above will not because value_type of dMap is different than dList.

    >
    > You just picked the wrong algorithm -- try std::transform instead. Use
    > a predicate which returns the relevant field (.second in this case) of
    > each pair in the map, and std::transform will insert them into the
    > list for you. For instance:
    >
    > #include <functional>
    >
    > struct get_second
    > : std::unary_function<std::map<int, Drive *>::value_type,
    > Drive *> {
    > result_type operator() (argument_type p) const {
    > return p.second;
    > }
    > };
    >
    > void xform (const std::map<int, Drive*> &dMap,
    > std::list<Drive*> &dList) {
    > std::transform(dMap.begin(), dMap.end(),
    > std::back_inserter(dList), get_second());
    > }
    >
    > In my code, I might use boost::bind from Boost.org instead of that
    > custom get_second struct, like so:
    >
    > #include <boost/bind.hpp>
    >
    > void xform (const std::map<int, Drive*> &dMap,
    > std::list<Drive*> &dList) {
    > typedef std::map<int, Drive*>::value_type pair_type;
    > std::transform(dMap.begin(), dMap.end(),
    > std::back_inserter(dList),
    > boost::bind(&pair_type::second, _1));
    > }
    >
    > > Now, I would like to wrap the map iterators inside a class class (let's

    call
    > > it WrapMap)
    > >
    > > WrapMap wm(dMap.begin(), dMap.end() );
    > >
    > > Now,
    > > copy( wm.begin(), wm.end(), back_inserter(dList) ); // this should work
    > >
    > > This means that operator* and operator++ need to be implemented for
    > > "iterator" that is associated with WrapMap. Of course, begin and end

    should
    > > return the associated WrapMap iterator.
    > >
    > > Am I heading in the right direction here?

    >
    > First, if the std::transform stuff above works for you, you probably
    > should use that instead. Second, if you really do want to wrap the
    > iterators, then just wrap the iterators, not the whole map. Third,
    > this has already been done, again by the Boost.org people:
    >
    > #include <boost/iterator_adaptors.hpp>
    > // using get_second as defined above
    >
    > void xform (const std::map<int, Drive*> &dMap,
    > std::list<Drive*> &dList) {
    > get_second gs;
    > std::copy(boost::make_transform_iterator(dMap.begin(), gs),
    > boost::make_transform_iterator(dMap.end(), gs),
    > std::back_inserter(dList));
    > }
    >
    > Oddly enough, the transform iterator adapter doesn't work with
    > boost::bind and a pointer-to-member as I did at the top -- "forming
    > pointer to reference." Grr.
    >
    > - Shane


    I want to use this generically - not only for the copy method. I want to use
    it for "for_each" or "copy" or "remove_if" etc... Also, I might it even more
    generic than I originally stated, i.e., be able to return a first or a
    second.
     
    sks_cpp, Jul 9, 2003
    #7
  8. "sks_cpp" <> wrote in message
    news:gsIOa.525983$...
    | > This can be done from scratch with code like this:
    ......
    | > Note that the iterator library of www.boost.org has some
    | > helper classes to help avoid writing all the boilerplate
    | > code for each iterator.
    |
    | Now, the boost code is public domain; to use freely or do you have to buy
    | (install) their libraries? I did look at their code but that is way out
    | there. I am not a beginner c++ programmer but templates are another thing
    | and then you have iterators in combination with templates... Anyway thanks
    | for your help.

    All the iterators in the standard library are templates, so you
    shouldn't be afraid of using them. Also, the code I posted earlier
    is self-contained and functional - you can use it as is.
    It doesn't need to use templates, but this allows it to apply
    to any std::map (and even other containers of std::pair or related).

    The use of boost libraries is totally unrestricted and free. They
    are peer-reviewed libraries geared towards being proposed for
    inclusion in a future C++ standard. They extend the current
    standard library and provide a convenient toolbox -- such as the
    popular shared_ptr, which simplifies memory management and
    supports containers of polymorphic objects.
    Many of the tools it provides should not be obscure once you
    master the standard C++ library ( for this I would recommend
    the study of http://www.josuttis.com/libbook/index.html ).

    To answer your question of another post, the Loki library is
    derived from a generic toolbox presented by Andrei Alexandrescu
    in his book: www.modercppdesign.com. But if boost turns you off,
    you'll probably want to wait before getting into this...


    hth,
    --
    Ivan Vecerina, Dr. med. <> http://www.post1.com/~ivec
    Brainbench MVP for C++ <> http://www.brainbench.com
     
    Ivan Vecerina, Jul 9, 2003
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. alex
    Replies:
    1
    Views:
    651
    Lau Lei Cheong
    Feb 4, 2005
  2. Matthias Hildebrand
    Replies:
    5
    Views:
    7,985
    krogers
    Mar 20, 2012
  3. Alex
    Replies:
    2
    Views:
    1,239
  4. Replies:
    26
    Views:
    2,123
    Roland Pibinger
    Sep 1, 2006
  5. ittium
    Replies:
    4
    Views:
    317
    ittium
    Dec 8, 2011
Loading...

Share This Page