copy map to a list

S

sks_cpp

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

Ivan Vecerina

| 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,
 
S

Shane Beasley

sks_cpp said:
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
 
T

tonci.tomic

sks_cpp said:
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
 
S

sks_cpp

sks_cpp said:
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&

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

_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?
 
S

sks_cpp

Ivan Vecerina said:
| 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.
 
S

sks_cpp

Shane Beasley said:
"sks_cpp" <[email protected]> wrote in message

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));
}


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.
 
I

Ivan Vecerina

| > 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,
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top