By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,089 Members | 1,262 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,089 IT Pros & Developers. It's quick & easy.

how to use for_each to collect some info from a vector into anothervector

P: n/a
Hi,
I am not familiar with for_each very well, suppoase I have a
vector<pair<unsigned int, unsigned int> > vec1 and the contents are

{<0x00000000, 0x000000FF>, <0x10000000, 0x2FFFFFFF>}

what I want is to create another vector, vector<int> vec2, which store
all the first 8 bit heads of the integer in vec1, for the above example,

0x00000000 & 0xFF000000 ==> 0x00000000,
0x000000FF & 0xFF000000 ==> 0x00000000,
0x10000000 & 0xFF000000 ==> 0x10000000,
0x2FFFFFFF & 0xFF000000 ==> 0x2F000000,

then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.

It's easy to specifically write a for loop, just wonder how to do it
use for_each.

Thanks.
Jul 22 '05 #1
Share this Question
Share on Google+
18 Replies


P: n/a
John Black wrote:
I am not familiar with for_each very well, suppoase I have a
vector<pair<unsigned int, unsigned int> > vec1 and the contents are

{<0x00000000, 0x000000FF>, <0x10000000, 0x2FFFFFFF>}

what I want is to create another vector, vector<int> vec2, which store
all the first 8 bit heads of the integer in vec1, for the above example,

0x00000000 & 0xFF000000 ==> 0x00000000,
0x000000FF & 0xFF000000 ==> 0x00000000,
0x10000000 & 0xFF000000 ==> 0x10000000,
0x2FFFFFFF & 0xFF000000 ==> 0x2F000000,

then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.

It's easy to specifically write a for loop, just wonder how to do it
use for_each.


You will have to implement a functor that will do that. Boost library
has some mechanisms that are not available in the standard library yet.
For example, there is no simple functor to extract 'first' or 'second'
from a pair.

Something like:

struct skim_pairs_to {
vector<int>& collector;
skim_pairs_to(vector<int>& c) : collector(c) {}
void operator()(const std::pair<unsigned,unsigned>& p) {
collector.push_back(p.first & 0xff000000);
collector.push_back(p.second & 0xff000000);
}
};

...
std::for_each(vec1.begin(), vec1.end(), skim_pairs_to(vec2));

should do it. I didn't test the code.

Victor
Jul 22 '05 #2

P: n/a
John Black <bl***@eed.com> wrote:
Hi,
I am not familiar with for_each very well, suppoase I have a
vector< pair< unsigned int, unsigned int > > vec1 and the contents are

{ < 0x00000000, 0x000000FF >, < 0x10000000, 0x2FFFFFFF > }

what I want is to create another vector, vector< int > vec2, which store
all the first 8 bit heads of the integer in vec1, for the above example,

0x00000000 & 0xFF000000 == > 0x00000000,
0x000000FF & 0xFF000000 == > 0x00000000,
0x10000000 & 0xFF000000 == > 0x10000000,
0x2FFFFFFF & 0xFF000000 == > 0x2F000000,

then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.
You only put 3 items in vec2, was that on purpose? IE are repeted values
not supposed to be entered?

If that's the case, I would insert into a set first, then copy from the
set to the vector (see below...)

It's easy to specifically write a for loop, just wonder how to do it
use for_each.


The same way, except the loop body would be in a functor. So you might
start with:

for ( vector< pair< unsigned, unsigned > >::iterator it = v.begin();
it != v.end(); ++it )
{
v2.push_back( it->first & 0xFF000000 );
v2.push_back( it->second & 0xFF000000 );
}

This would become:

struct filler {
vector< unsigned >& v;
filler( vector< unsigned >& v ): v( v ) { }
void operator()( const pair< unsigned, unsigned >& p ) {
v.push_back( p.first & 0xFF000000 );
v.push_back( p.second & 0xFF000000 );
}
};

and:

for_each( v.begin(), v.end(), filler( v2 ) );

Seems like a bit of a waste. We've created a new type, that can only be
used in this one place, and when someone encounters the 'for_each' he
needs to search the code to find out what this new type does.

What if we could make something more resuable, and at the same time do a
better job of expressing what is happening at the place where it is
supposed to happen?

Let's take a look at what we are doing. Basically it's a transform
except each value in the first container is being transformed twice and
placed in the second container. So we can model something off of
std::transform.

template < typename InputIter, typename OutputIter,
typename Op1, typename Op2 >
OutputIter expanding_transform( InputIter first, InputIter last,
OutputIter result, Op1 op1, Op2 op2 )
{
while ( first != last )
{
*result++ = op1( *first );
*result++ = op2( *first );
++first;
}
return result;
}

Maybe the above isn't all that reusable, but it's certanly more resuable
than the 'filler' type above. For example, we can use this function to
output our vector< pair< unsigned, unsigned > > to cout... The fact that
we can already see two uses for this function argues well for its
reusablity.

Now, what arguments do we need to pass into this function? The first two
are easy 'v.begin()' and 'v.end()' we see this all the time in the
standard algorithms. The third is a little harder, but still often seen:
'back_inserter( v2 )'. Of course 'v' is our vector< pair< unsigned,
unsigned > > and 'v2' is our new vector< unsigned >... For the last two
parameters, we need to do some more work.

First we examine the 'functional' part of the stl. We find a
'logical_and' functor, but no 'bit_and'. Oh well, that's easy to fix:

template < typename T >
struct bit_and : public std::binary_function< T, T, T >
{
T operator()( const T& x, const T& y ) const { return x & y; }
};

So, for each of the Ops in our expanding_transform, we need to call
'bit_and' were the first argument is the first and second item in the
pair, and the second argument is 0xFF000000. Let's make a functor that
does that:

binder2nd< bit_and< unsigned > > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );

Let's make sure we know what high_8_mask does:

assert( high_8_mask( 0x12345678 ) == 0x12000000 );

Unfortunatly, we can't just pass our pair< unsigned, unsigned > into the
above because it only takes one unsigned value.

Now we have to look in the past. The origional STL had several useful
functors that never made it into the standard. Two of them specifically
dealt with manipulating pair objects so that they could be used in
standard functors: select1st and select2nd. You can find them on SGI's
website and I'm sure other websites have them. They both do exactly what
you would think. You pass in a pair object, and it returns either the
first or second object of the pair.

Another useful functor is 'unary_compose'; which takes two other
functors and combines them like this: f1( f2( x ) ). There is also a
useful function 'compose1' that helps build a unary_compose objects (
like the way 'make_pair' builds 'pair' objects. ) You can also find this
in boost where it's called 'compose_f_gx'...

With these three functors in our arsenal we can build the functors that
will be used by our new algorithm.

I also want to make the pair easer to work with so I'll make a typedef.

Now I'll put all of this together to show how it works:

typedef pair< unsigned, unsigned > two_flags;

binder2nd< bit_and< unsigned > > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );

expanding_transform( v.begin(), v.end(), back_inserter( v2 ),
compose1( high_8_mask, select1st< two_flags >() ),
compose1( high_8_mask, select2nd< two_flags >() ) );

There you go, we have written the loop using lots of small, highly
reusable components.

Now back to my question above about no repeat values. If that's the case
then insert into a set:

set< unsigned > s;
binder2nd< bit_and<unsigned int> > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );
expanding_transform( v.begin(), v.end(),
inserter( s, s.begin() ),
compose1( high_8_mask, select1st< two_flags >() ),
compose1( high_8_mask, select2nd< two_flags >() ) );
copy( s.begin(), s.end(), back_inserter( v2 ) );
Jul 22 '05 #3

P: n/a
John Black <bl***@eed.com> wrote in message news:<40***************@eed.com>...
Hi,
I am not familiar with for_each very well, suppoase I have a
vector<pair<unsigned int, unsigned int> > vec1 and the contents are

{<0x00000000, 0x000000FF>, <0x10000000, 0x2FFFFFFF>}

what I want is to create another vector, vector<int> vec2, which store
all the first 8 bit heads of the integer in vec1, for the above example,

0x00000000 & 0xFF000000 ==> 0x00000000,
0x000000FF & 0xFF000000 ==> 0x00000000,
0x10000000 & 0xFF000000 ==> 0x10000000,
0x2FFFFFFF & 0xFF000000 ==> 0x2F000000,

then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.

It's easy to specifically write a for loop, just wonder how to do it
use for_each.


IMO, you're getting the steps out of order. First you need to pick
the right algorithm, THEN you need to figure out how to use it.

In this case, std::transform is MUCH better suited to the job (at
least IMO).

// warning: this code is incomplete and therefore untested.

// save a little typing:
typedef std::pair<unsigned int, unsigned int> dt;

// define what we're going to do to each item:
struct top8 {
unsigned int operator()(dt const &d) {
// assumes 32-bit ints.
return d.first & 0xff000000;
}
};

// define vectors for input and output:
std::vector<dt> vec1;
std::vector<unsigned int> vec2;

// code to fill vec1 goes here.

// transform the input into the output:
std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2),
top8);

Arrogant prediction: nobody will post a better solution using
for_each. :-)

P.S. Of course, I get to define "better". <G>

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jul 22 '05 #4

P: n/a
"Jerry Coffin" <jc*****@taeus.com> wrote in message
{<0x00000000, 0x000000FF>, <0x10000000, 0x2FFFFFFF>} then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.

Maybe one element missing?

struct top8 { std::vector<dt> vec1;
std::vector<unsigned int> vec2;

// code to fill vec1 goes here.

// transform the input into the output:
std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2),
top8);


But we want tyo iterate over vec1[0].first then vec1[0].second then
vec1[1].first then vec[1].second. For this we need to write a segmented
iterator (ie. a double iterator). Then

std::transform(OverPair(vec1.begin()), OverPair(vec1.end()),
std::back_inserter(vec2), top8);
Jul 22 '05 #5

P: n/a
In article <b2*************************@posting.google.com> ,
jc*****@taeus.com (Jerry Coffin) wrote:
IMO, you're getting the steps out of order. First you need to pick
the right algorithm, THEN you need to figure out how to use it.
True.

In this case, std::transform is MUCH better suited to the job (at
least IMO).

// warning: this code is incomplete and therefore untested.

// save a little typing:
typedef std::pair<unsigned int, unsigned int> dt;

// define what we're going to do to each item:
struct top8 {
unsigned int operator()(dt const &d) {
// assumes 32-bit ints.
return d.first & 0xff000000;
}
};

// define vectors for input and output:
std::vector<dt> vec1;
std::vector<unsigned int> vec2;

// code to fill vec1 goes here.

// transform the input into the output:
std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2),
top8);

Arrogant prediction: nobody will post a better solution using
for_each. :-)


Much too arrogant. Your code fails to do what the OP wanted done. Try
again. But I mean this. Please try again because I couldn't figure out a
solution without writing a new algorithm and I'd love to see if it can
be done using transform.
Jul 22 '05 #6

P: n/a
In article <WH*******************@bgtnsc04-news.ops.worldnet.att.net>,
"Siemel Naran" <Si*********@REMOVE.att.net> wrote:
std::vector<dt> vec1;
std::vector<unsigned int> vec2;

// code to fill vec1 goes here.

// transform the input into the output:
std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2),
top8);


But we want tyo iterate over vec1[0].first then vec1[0].second then
vec1[1].first then vec[1].second. For this we need to write a segmented
iterator (ie. a double iterator). Then

std::transform(OverPair(vec1.begin()), OverPair(vec1.end()),
std::back_inserter(vec2), top8);


I'd love to see what this "OverPair" iterator looks like. Care to post
it?
Jul 22 '05 #7

P: n/a
"Siemel Naran" <Si*********@REMOVE.att.net> wrote in message news:<WH*******************@bgtnsc04-news.ops.worldnet.att.net>...
"Jerry Coffin" <jc*****@taeus.com> wrote in message
{<0x00000000, 0x000000FF>, <0x10000000, 0x2FFFFFFF>} then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.

Maybe one element missing?


Probably -- I didn't read it carefully enough, and got confused by the
inconsistency.

[ my incorrect code elided ... ]
But we want tyo iterate over vec1[0].first then vec1[0].second then
vec1[1].first then vec[1].second. For this we need to write a segmented
iterator (ie. a double iterator). Then

std::transform(OverPair(vec1.begin()), OverPair(vec1.end()),
std::back_inserter(vec2), top8);


That certainly looks a lot better, provided that my reread of the
requirements isn't wrong (again).

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jul 22 '05 #8

P: n/a
jc*****@taeus.com (Jerry Coffin) wrote:
But we want tyo iterate over vec1[0].first then vec1[0].second then
vec1[1].first then vec[1].second. For this we need to write a segmented
iterator (ie. a double iterator). Then

std::transform(OverPair(vec1.begin()), OverPair(vec1.end()),
std::back_inserter(vec2), top8);


That certainly looks a lot better, provided that my reread of the
requirements isn't wrong (again).


I've been playing around this this for a bit. At this point, I don't
think the requirements can be met using std::transform. There is simply
no way to write "OverPair" to make this work. I'd love to be proven
wrong though...
Jul 22 '05 #9

P: n/a
"Daniel T." <po********@eathlink.net> wrote in message
news:po******************************@news6.west.e arthlink.net...
jc*****@taeus.com (Jerry Coffin) wrote:

But we want tyo iterate over vec1[0].first then vec1[0].second then
vec1[1].first then vec[1].second. For this we need to write a segmented iterator (ie. a double iterator). Then

std::transform(OverPair(vec1.begin()), OverPair(vec1.end()),
std::back_inserter(vec2), top8);


That certainly looks a lot better, provided that my reread of the
requirements isn't wrong (again).


I've been playing around this this for a bit. At this point, I don't
think the requirements can be met using std::transform. There is simply
no way to write "OverPair" to make this work. I'd love to be proven
wrong though...


Like a std::deque::iterator, the outer loop loops over the list nodes, and
the inner loops over the the elements of a vector. We want the outer loop
to loop over the elements of a vector, and the inner to loop over the first
and second. Something like:

class OverPair {
public:
/* the usual 5 typedefs: iterator_category, reference, etc */
OverPair(std::vector<unsigned>::iterator outer) : d_outer(outer),
d_inner(FIRST) { }
friend bool operator==(const OverPair&, const OverPair&) const {
return lhs.d_outer == rhs.d_outer && lhs.d_inner == rhs.d_inner;
}
reference operator*() {
Pair& pair = *d_outer;
switch (d_inner) {
case FIRST: return pair.first;
case SECOND: return pair.second;
}
return Pair();
}
OverPair operator++() {
++d_inner;
if (d_inner > SECOND) {
d_inner = FIRST;
++d_outer;
}
return *this;
}
private:
typedef std::pair<unsigned, unsigned> Pair;
enum Element { FIRST, SECOND };
std::vector<Pair>::iterator d_outer;
Element d_inner;
};

Of course, one has to wonder whether the STL functional approach is worth
the trouble as opposed to write an explicit for loop. Sometimes it might
be, as when we want to free ourselves from the logic of segemented
iterators, and use many different algorithms.
Jul 22 '05 #10

P: n/a
In article <Iz*******************@bgtnsc04-news.ops.worldnet.att.net>,
"Siemel Naran" <Si*********@REMOVE.att.net> wrote:
"Daniel T." <po********@eathlink.net> wrote in message
news:po******************************@news6.west. earthlink.net...
jc*****@taeus.com (Jerry Coffin) wrote:
>> But we want tyo iterate over vec1[0].first then vec1[0].second then
>> vec1[1].first then vec[1].second. For this we need to write asegmented >> iterator (ie. a double iterator). Then
>>
>> std::transform(OverPair(vec1.begin()), OverPair(vec1.end()),
>> std::back_inserter(vec2), top8);
>
>That certainly looks a lot better, provided that my reread of the
>requirements isn't wrong (again).


I've been playing around this this for a bit. At this point, I don't
think the requirements can be met using std::transform. There is simply
no way to write "OverPair" to make this work. I'd love to be proven
wrong though...


class OverPair {

[snip]

I almost ignored what you wrote because it didn't compile, but then the
light came on. Thank you... I went ahead and wrote it up as a template
and cleaned it up a bit:

template < typename Iter >
class OverPair:
public iterator<forward_iterator_tag,
typename Iter::value_type::first_type >
{
bool onFirst;
Iter it;
public:
OverPair( Iter i ): onFirst( true ), it( i ) { }

typename Iter::value_type::first_type& operator*() {
if ( onFirst )
return it->first;
return it->second;
}

bool onFirstElem() const { return onFirst; }
const Iter& iter() const { return it; }

OverPair& operator++() {
if ( !onFirst ) {
++it;
}
onFirst = !onFirst;
return *this;
}

OverPair operator++(int) {
OverPair temp( *this );
++*this;
return temp;
}
};

template < typename Iter >
bool operator==( const OverPair<Iter>& lhs, const OverPair<Iter>& rhs ) {
return lhs.onFirstElem() == rhs.onFirstElem() &&
lhs.iter() == rhs.iter();
}

template < typename Iter >
bool operator!=( const OverPair<Iter>& lhs, const OverPair<Iter>& rhs )
{ return !( lhs == rhs ); }

template < typename Iter >
OverPair<Iter> over_pair( Iter it ) {
return OverPair<Iter>(it);
}

Then it would be used like this:

binder2nd< bit_and<unsigned int> > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );
transform( over_pair(v.begin()), over_pair(v.end()),
back_inserter(v2), high_8_mask );

Of course, one has to wonder whether the STL functional approach is worth
the trouble as opposed to write an explicit for loop. Sometimes it might
be, as when we want to free ourselves from the logic of segemented
iterators, and use many different algorithms.


Well there is also the fact that the origional loop wasn't even remotly
reusable. The above code, on the other hand, can be used to load our
vector<pair<unsigned, unsigned> > from a stream, or write it to a stream
(making testing the values within it much easer.) That's three uses
already and I'm not even trying...
Jul 22 '05 #11

P: n/a
In article <po******************************@news1.west.earth link.net>,
"Daniel T." <po********@eathlink.net> wrote:
In article <Iz*******************@bgtnsc04-news.ops.worldnet.att.net>,
"Siemel Naran" <Si*********@REMOVE.att.net> wrote:
"Daniel T." <po********@eathlink.net> wrote in message
news:po******************************@news6.west .earthlink.net...
jc*****@taeus.com (Jerry Coffin) wrote:

>> But we want tyo iterate over vec1[0].first then vec1[0].second then
>> vec1[1].first then vec[1].second. For this we need to write a

segmented
>> iterator (ie. a double iterator). Then
>>
>> std::transform(OverPair(vec1.begin()), OverPair(vec1.end()),
>> std::back_inserter(vec2), top8);
>
>That certainly looks a lot better, provided that my reread of the
>requirements isn't wrong (again).

I've been playing around this this for a bit. At this point, I don't
think the requirements can be met using std::transform. There is simply
no way to write "OverPair" to make this work. I'd love to be proven
wrong though...


class OverPair {

[snip]

I almost ignored what you wrote because it didn't compile, but then the
light came on. Thank you... I went ahead and wrote it up as a template
and cleaned it up a bit


[snipped code]

I'm normally not one to reply to my own posts, but I've been thinking
about the solutions presented so far:

The basic loop, has absolutly no reuse value but expresses itself
clearly to even the most raw beginner.

for_each and a custom functor, also has little to no reuse value and
removes to locality of reference that the loop has, which makes it
harder to understand.

Segmented iterator, has a slightly higher reuse potential and once you
know how the OverPair iterator works, is easy to understand (although
comming up with it wasn't very intuitave for me.)

expanding_transform algorithm, has the greatest reuse potential while
requiring a better undersanding of how to compose functors.

I think the basic loop is only easer to understand for beginners because
of the way most books teach C++, starting out as a "better C" and going
up from there. I expect that someone who learned C++ from the library
down rather than from pointers up, would find one of the other solutions
more natural.
Jul 22 '05 #12

P: n/a
"Daniel T." <po********@eathlink.net> wrote in message news:postmaster-
"Siemel Naran" <Si*********@REMOVE.att.net> wrote: I almost ignored what you wrote because it didn't compile, but then the
light came on. Thank you... I went ahead and wrote it up as a template
and cleaned it up a bit:
What you have is good, but there were just some minor errors.
class OverPair {
public:
/* the usual 5 typedefs: iterator_category, reference, etc */
The above includes

typedef unsigned& reference;
OverPair(std::vector<unsigned>::iterator outer) : d_outer(outer),
d_inner(FIRST) { }
Above line is bullshit. We have a vector of pair<unsigned,unsigned>. So
change that to

typedef std::pair<unsigned, unsigned> Pair;
OverPair(std::vector<Pair>::iterator outer) : d_outer(outer),
d_inner(FIRST) { }
friend bool operator==(const OverPair&, const OverPair&) const {
return lhs.d_outer == rhs.d_outer && lhs.d_inner == rhs.d_inner;
}
Mistake above is to make member function const. Remove the const. Also
name the variables lhs and rhs.

friend bool operator==(const OverPair& lhs, const OverPair& rhs) {
return lhs.d_outer == rhs.d_outer && lhs.d_inner == rhs.d_inner;
}
reference operator*() {
Pair& pair = *d_outer;
switch (d_inner) {
case FIRST: return pair.first;
case SECOND: return pair.second;
}
return Pair();
}
Compiler gives me error that last line should return a lvalue. Of course,
this line is never reached. So change to

reference operator*() {
Pair& pair = *d_outer;
if (d_inner == FIRST) return pair.first;
return pair.second;
}

OverPair operator++() {
++d_inner;
Compiler complains for the above line. Either overload operator++ for the
enum or use

d_inner = Element(d_inner+1);

if (d_inner > SECOND) {
d_inner = FIRST;
++d_outer;
}
return *this;
} private:
typedef std::pair<unsigned, unsigned> Pair;
Remove the above line as we added it earlier.
enum Element { FIRST, SECOND };
std::vector<Pair>::iterator d_outer;
Element d_inner;
}; template < typename Iter >
class OverPair:
public iterator<forward_iterator_tag,
typename Iter::value_type::first_type >
{
bool onFirst;
Iter it;
public:
OverPair( Iter i ): onFirst( true ), it( i ) { }

typename Iter::value_type::first_type& operator*() {
if ( onFirst )
return it->first;
return it->second;
}

bool onFirstElem() const { return onFirst; }
const Iter& iter() const { return it; }

OverPair& operator++() {
if ( !onFirst ) {
++it;
}
onFirst = !onFirst;
return *this;
}

OverPair operator++(int) {
OverPair temp( *this );
++*this;
return temp;
}
};

template < typename Iter >
bool operator==( const OverPair<Iter>& lhs, const OverPair<Iter>& rhs ) {
return lhs.onFirstElem() == rhs.onFirstElem() &&
lhs.iter() == rhs.iter();
}

template < typename Iter >
bool operator!=( const OverPair<Iter>& lhs, const OverPair<Iter>& rhs )
{ return !( lhs == rhs ); }

template < typename Iter >
OverPair<Iter> over_pair( Iter it ) {
return OverPair<Iter>(it);
}

Then it would be used like this:

binder2nd< bit_and<unsigned int> > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );
transform( over_pair(v.begin()), over_pair(v.end()),
back_inserter(v2), high_8_mask );


Yes, it's essentially the same concept.

Of course, one has to wonder whether the STL functional approach is worth
the trouble as opposed to write an explicit for loop. Sometimes it might
be, as when we want to free ourselves from the logic of segemented
iterators, and use many different algorithms.


Well there is also the fact that the origional loop wasn't even remotly
reusable. The above code, on the other hand, can be used to load our
vector<pair<unsigned, unsigned> > from a stream, or write it to a stream
(making testing the values within it much easer.) That's three uses
already and I'm not even trying...


But is it worth the trouble to write such a complex iterator class? It
certainly could be, but I'm not totally convinced as yet. Just keeping an
open mind.
Jul 22 '05 #13

P: n/a
"Daniel T." <po********@eathlink.net> wrote in message news:postmaster-
The basic loop, has absolutly no reuse value but expresses itself
clearly to even the most raw beginner.
Which one was the basic loop?
for_each and a custom functor, also has little to no reuse value and
removes to locality of reference that the loop has, which makes it
harder to understand.
Yes, that's the trouble I have with for_each. Though if you can use
existing binders and functors like std::equal and the ones in boost, you can
make the intent clear in the calling code. But on the other hand, there's a
high learning curve to understanding these functors. Sure, std::equal makes
sense as does std::bind2nd, but throw them together and the resulting code
looks a tad intimidating. Also, there's a proposal to enhance the C++
standard to allow local classes to have an external linkage. This would
allow us to define the class inside the function that uses it in a call to
for_each. This could be a nice boost (sorry for the bad pun :) to the use
of for_each, transform, and the others.
Segmented iterator, has a slightly higher reuse potential and once you
know how the OverPair iterator works, is easy to understand (although
comming up with it wasn't very intuitave for me.)
Sure, the segmented iterator is a challenge, but now you know how to write a
std::deque::iterator.
expanding_transform algorithm, has the greatest reuse potential while
requiring a better undersanding of how to compose functors.


What is expanding_transform?

Jul 22 '05 #14

P: n/a
In article <gp******************@bgtnsc04-news.ops.worldnet.att.net>,
"Siemel Naran" <Si*********@REMOVE.att.net> wrote:
"Daniel T." <po********@eathlink.net> wrote in message news:postmaster-
The basic loop, has absolutly no reuse value but expresses itself
clearly to even the most raw beginner.


Which one was the basic loop?


for ( vector< pair< unsigned, unsigned > >::iterator it = v.begin();
it != v.end(); ++it )
{
v2.push_back( it->first & 0xFF000000 );
v2.push_back( it->second & 0xFF000000 );
}
for_each and a custom functor, also has little to no reuse value and
removes to locality of reference that the loop has, which makes it
harder to understand.


Yes, that's the trouble I have with for_each. Though if you can use
existing binders and functors like std::equal and the ones in boost, you can
make the intent clear in the calling code. But on the other hand, there's a
high learning curve to understanding these functors. Sure, std::equal makes
sense as does std::bind2nd, but throw them together and the resulting code
looks a tad intimidating.


Only because we were taught C++ "from the ground up". First as a "better
C", with the libraries coming last. I suspect that someone who was
taught C++ from the libraries down (much like in the book "Accelerated
C++" this would be much less of an issue.

IMO, proper use of the standard library (especially the algorithms and
functors) is what makes someone a C++ programmer, rather than a
programmer who happens to use C++.

expanding_transform algorithm, has the greatest reuse potential while
requiring a better understanding of how to compose functors.


What is expanding_transform?


That was my solution to the problem presented:

Write a new algorithm:

template < typename InputIter, typename OutputIter,
typename Op1, typename Op2 >
OutputIter expanding_transform( InputIter first, InputIter last,
OutputIter result, Op1 op1, Op2 op2 )
{
while ( first != last )
{
*result++ = op1( *first );
*result++ = op2( *first );
++first;
}
return result;
}

Then use a couple of functors that came in STL (but didn't make it into
the standard) to produce:

typedef pair< unsigned, unsigned > two_flags;

binder2nd< bit_and< unsigned > > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );

expanding_transform( v.begin(), v.end(), back_inserter( v2 ),
compose1( high_8_mask, select1st< two_flags >() ),
compose1( high_8_mask, select2nd< two_flags >() ) );

expanding_transform has more reuse potential than OverPair because it
can be used on input that *isn't* a pair.
Jul 22 '05 #15

P: n/a
"Daniel T." <po********@eathlink.net> wrote:
(Jerry Coffin) wrote:

[snip lots of complicated crap]
Arrogant prediction: nobody will post a better solution using
for_each. :-)


Much too arrogant. Your code fails to do what the OP wanted done. Try
again. But I mean this. Please try again because I couldn't figure out a
solution without writing a new algorithm and I'd love to see if it can
be done using transform.


#include <algorithm>
#include <utility>
#include <vector>

typedef std::pair<unsigned int, unsigned int> upair;

unsigned int head(upair p1, upair p2)
{ return p1.first & p2.second & 0xFF000000; }

// ...
std::vector< upair > vec;
// ...

std::vector< uint > out(vec.size());
std::transform(vec.begin(), vec.end(), vec.begin(), out.begin(), head);
Jul 22 '05 #16

P: n/a
In article <84**************************@posting.google.com >,
ol*****@inspire.net.nz (Old Wolf) wrote:
"Daniel T." <po********@eathlink.net> wrote:
(Jerry Coffin) wrote:

[snip lots of complicated crap]
>Arrogant prediction: nobody will post a better solution using
>for_each. :-)


Much too arrogant. Your code fails to do what the OP wanted done. Try
again. But I mean this. Please try again because I couldn't figure out a
solution without writing a new algorithm and I'd love to see if it can
be done using transform.


#include <algorithm>
#include <utility>
#include <vector>

typedef std::pair<unsigned int, unsigned int> upair;

unsigned int head(upair p1, upair p2)
{ return p1.first & p2.second & 0xFF000000; }

// ...
std::vector< upair > vec;
// ...

std::vector< uint > out(vec.size());
std::transform(vec.begin(), vec.end(), vec.begin(), out.begin(), head);


Still doesn't work. After the transform is complete, out.size() will
equal vec.size() which is not what the OP wanted. He wanted out.size()
to equal vec.size() * 2.
Jul 22 '05 #17

P: n/a
"Daniel T." <po********@eathlink.net> wrote:
Old Wolf wrote:
"Daniel T." <po********@eathlink.net> wrote:
Much too arrogant. Your code fails to do what the OP wanted done. Try
again. But I mean this. Please try again because I couldn't figure out a
solution without writing a new algorithm and I'd love to see if it can
be done using transform.

std::vector< uint > out(vec.size());
std::transform(vec.begin(), vec.end(), vec.begin(), out.begin(), head);


Still doesn't work. After the transform is complete, out.size() will
equal vec.size() which is not what the OP wanted. He wanted out.size()
to equal vec.size() * 2.


Ah. I misread the OP's question (several times..) , his input had
2 pairs and 3 outputs (so I guess 2 outputs was as good a guess as 4 :)
In that case, I think std::transform is not appropriate, as the output
list has to be the same size as the input list. I'd stick with for_each.

OTOH, I wonder if he did that on purpose and wants his output vector
to not repeat duplicates..
Jul 22 '05 #18

P: n/a
In article <84**************************@posting.google.com >,
ol*****@inspire.net.nz (Old Wolf) wrote:
"Daniel T." <po********@eathlink.net> wrote:
Old Wolf wrote:
>"Daniel T." <po********@eathlink.net> wrote:
>> Much too arrogant. Your code fails to do what the OP wanted done. Try
>> again. But I mean this. Please try again because I couldn't figure out a
>> solution without writing a new algorithm and I'd love to see if it can
>> be done using transform.
> std::vector< uint > out(vec.size());
> std::transform(vec.begin(), vec.end(), vec.begin(), out.begin(), head);


Still doesn't work. After the transform is complete, out.size() will
equal vec.size() which is not what the OP wanted. He wanted out.size()
to equal vec.size() * 2.


Ah. I misread the OP's question (several times..) , his input had
2 pairs and 3 outputs (so I guess 2 outputs was as good a guess as 4 :)
In that case, I think std::transform is not appropriate, as the output
list has to be the same size as the input list. I'd stick with for_each.


As has been shown, it *can* be done with transform as long as you have
an iterator that can handle it. But overall, I agree with you. I think
it better to make a new algorithm for this problem, that can also be
used in other related problems...

OTOH, I wonder if he did that on purpose and wants his output vector
to not repeat duplicates..


The simple solution there is to output into a set first, then copy the
set to the output vector (if necessary.) It becomes much harder if the
items need to be kept in the same order though. In that case, one would
be forced to use a custom iterator that keeps track internaly what items
have been added to the output (ie the iterator would contain a set
object.)
Jul 22 '05 #19

This discussion thread is closed

Replies have been disabled for this discussion.