STL question

R

Rusty

Is there any way to use the STL algorithm for_each if my container
contains pointers? For example,

class A
{
int a;
virtual void print (void) {cout << a << endl;}
};
class B: public A
{
int b;
virtual void print (void) {cout << a << "," << b << endl;}
}

I want to have a list that I can call print() on for each member, so I
figured vector <A*>. Is there anyway to get the following with
for_each?

vector <A*>::iterator i;
for (i=list.begin(); i<list.end(); ++i) (*i)->print();

Russ
 
J

Jacques Labuschagne

Rusty said:
Is there any way to use the STL algorithm for_each if my container
contains pointers? For example,

class A
{
int a;
virtual void print (void) {cout << a << endl;}
};
class B: public A
{
int b;
virtual void print (void) {cout << a << "," << b << endl;}
}

I want to have a list that I can call print() on for each member, so I
figured vector <A*>. Is there anyway to get the following with
for_each?

Sure..

struct call_print{
void operator()(A* a){ a->print(); }
};

and then

for_each(v.begin(), v.end(), call_print());
vector <A*>::iterator i;
for (i=list.begin(); i<list.end(); ++i) (*i)->print();

Don't call your vector 'list', there's already a std::list class.
 
J

Jonathan Turkanis

Rusty said:
Is there any way to use the STL algorithm for_each if my container
contains pointers? For example,

class A
{
int a;
virtual void print (void) {cout << a << endl;}
};
class B: public A
{
int b;
virtual void print (void) {cout << a << "," << b << endl;}
}

I want to have a list that I can call print() on for each member, so I
figured vector <A*>. Is there anyway to get the following with
for_each?

struct Printer : std::unary_function<A*, void> {
void operator() (A* a) const { /* write to cout */ }
}

std::for_each(list.begin(), list.end(), Printer());

HTH.

Jonathan
 
D

Daniel T.

Rusty said:
Is there any way to use the STL algorithm for_each if my container
contains pointers? For example,

class A
{
int a;
virtual void print (void) {cout << a << endl;}
};
class B: public A
{
int b;
virtual void print (void) {cout << a << "," << b << endl;}
}

I want to have a list that I can call print() on for each member, so I
figured vector <A*>. Is there anyway to get the following with
for_each?

vector <A*>::iterator i;
for (i=list.begin(); i<list.end(); ++i) (*i)->print();

for_each( vec.begin(), vec.end(), mem_fun( &A::print ) );
 
J

Jacques Labuschagne

Daniel said:
for_each( vec.begin(), vec.end(), mem_fun( &A::print ) );

Hang on, it's a vector of pointers... Surely there's no way of getting
around the extra functor to dereference the pointer.

Jacques
 
J

Jerry Coffin

Sure..

struct call_print{
void operator()(A* a){ a->print(); }
};

Using operator<< to do formatted printing of an object is a widely known
idiom, so it's probably better (at least IMO) to use it to do this job.
I'd change the definitions a little bit so the member functions take the
stream to write to as a parameter instead of always writing to
std::cout, and return the stream they're writing to.

class A
{
// I've defined it to take the ostream as a parameter instead of
// always writing to cout.
virtual std::eek:stream &print (std::eek:stream &os) const {return os<<a;}

// since we've defined print to be private, make operator<< a friend
// so it can call print.
friend std::eek:stream &operator<<(std::eek:stream &, A const *);
protected:
// a can't be private if you're going to access it directly in B
int a;
public:
A(int init) : a(init) {}
};

class B: public A
{
int b;
std::eek:stream &print(std::eek:stream &os) const {
return os << a << "," << b;
}
public:
B(int inita, int initb) : A(inita), b(initb) {}
};

and then add the definition of operator<<:

std::eek:stream &operator<<(std::eek:stream &os, A const *a) {
return a->print(os);
}

IMO, std::for_each isn't really the best tool for the job at hand
either. We're copying the contents of the vector to a stream, so
std::copy is really the algorithm for the job at hand:

std::eek:stream_iterator<A*> out(std::cout, "\n");
std::vector<A*> a;

// code to populate 'a' elided.

std::copy(a.begin(), a.end(), out);
 
J

Jacques Labuschagne

Jonathan said:
mem_fun returns a function object taking a pointer argument, so this
should work. Of course, it only addresses the example, not the general
problem.

Right you are...

Thanks,
Jacques
 
J

Jonathan Turkanis

Jacques Labuschagne said:
Hang on, it's a vector of pointers... Surely there's no way of getting
around the extra functor to dereference the pointer.

Jacques

mem_fun returns a function object taking a pointer argument, so this
should work. Of course, it only addresses the example, not the general
problem.

Jonathan
 
J

Jumbo

Rusty said:
Is there any way to use the STL algorithm for_each if my container
contains pointers? For example,

class A
{
int a;
virtual void print (void) {cout << a << endl;}
};
class B: public A
{
int b;
virtual void print (void) {cout << a << "," << b << endl;}
}

I want to have a list that I can call print() on for each member, so I
figured vector <A*>. Is there anyway to get the following with
for_each?

vector <A*>::iterator i;
for (i=list.begin(); i<list.end(); ++i) (*i)->print();

Russ

Yes see code below:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Print{
public:
void operator()(const int* i)
{
cout<< *i << '\n';
}
};

int main(){
Print print;
vector<int*,allocator<int> > intArr(3);
int x=1;
int y=2;
int z=3;
intArr[0] = &x;
intArr[1] = &y;
intArr[2] = &z;

for_each( intArr.begin(), intArr.end(), print);

return 0;
}


HTH.
 
D

Daniel T.

Jacques Labuschagne said:
Hang on, it's a vector of pointers... Surely there's no way of getting
around the extra functor to dereference the pointer.

mem_fun returns a functor that dereferences the pointer.
 
D

Daniel T.

Jonathan Turkanis said:
mem_fun returns a function object taking a pointer argument, so this
should work.

Of course it should work, this is exactly the type of problem that
mem_fun was designed to solve.

Of course, it only addresses the example, not the general
problem.

It does address the general problem which was (from the OP):
Is there any way to use the STL algorithm for_each if my container
contains pointers?

The answer is, "Yes, one way is to use mem_fun."
 
J

Jonathan Turkanis

Daniel T. said:
Of course it should work, this is exactly the type of problem that
mem_fun was designed to solve.

Would you feel better if I said 'does' instead of 'should'? I know it
works; it was a normative 'should'.
It does address the general problem which was (from the OP):

I don't we disagree about anything important. The more general problem
is how to iterate over a container of pointers when the operation you
wish to perform doesn't happen to be a member function.

Jonathan
 
M

Martijn Lievaart

Is there any way to use the STL algorithm for_each if my container
contains pointers? For example,

class A
{
int a;
virtual void print (void) {cout << a << endl;}
};
class B: public A
{
int b;
virtual void print (void) {cout << a << "," << b << endl;}
}

I want to have a list that I can call print() on for each member, so I
figured vector <A*>. Is there anyway to get the following with
for_each?

vector <A*>::iterator i;
for (i=list.begin(); i<list.end(); ++i) (*i)->print();

Russ

vector <A*>::iterator i;
for_each (list.begin(), list.end(), mem_fun(&A::print));

HTH,
M4
 
D

Daniel T.

Jonathan Turkanis said:
The more general problem
is how to iterate over a container of pointers when the operation you
wish to perform doesn't happen to be a member function.

That's easy too.

for_each( vec.begin(), vec.end(), myFunc );

for_each works fine with function pointers.

If the function happens to be in a different object. IE

class A { };
class B {
public:
void func( A* a );
};

vector<A*> vec;
B b;

Then one simply does this:

for_each( vec.begin(), vec.end(), bind1st( mem_fun(&B::func), &b ) );
 
J

Jonathan Turkanis

Daniel T. said:
That's easy too.

for_each( vec.begin(), vec.end(), myFunc );

for_each works fine with function pointers.

This is what I mentioned in my original post.

I know how to use the STL. What is your point?

Jonathan
 
J

Jumbo

Rusty said:
Is there any way to use the STL algorithm for_each if my container
contains pointers? For example,

class A
{
int a;
virtual void print (void) {cout << a << endl;}
};
class B: public A
{
int b;
virtual void print (void) {cout << a << "," << b << endl;}
}

I want to have a list that I can call print() on for each member, so I
figured vector <A*>. Is there anyway to get the following with
for_each?

vector <A*>::iterator i;
for (i=list.begin(); i<list.end(); ++i) (*i)->print();

Russ

I found I need to use:
for (i=list.begin(); i<list.end(); ++i) i[0]->print();

Although it looks like your only ever indexing the first element it's not ,
it works properly because your indexing the iterator and not the vector.

HTH
 
R

Ron Natalie

Jumbo @uko2.co.uk> said:
vector <A*>::iterator i;
for (i=list.begin(); i<list.end(); ++i) (*i)->print();

Russ

I found I need to use:
for (i=list.begin(); i<list.end(); ++i) i[0]->print();

Although it looks like your only ever indexing the first element it's not ,
it works properly because your indexing the iterator and not the vector

It won't work properly if "list" is really a list and not a vector.
You're only guaranteed to be able to apply operator[] to random
access iterators.

His original code would have worked fine.

To get back to whether he could use for for_each. You could obviously define
your own functor for the third arg, but C++ provides an adapter already called
mem_fun

for_each(list.begin(), list.end(), mem_fun(&A::print));
 
R

Rusty

On Sun, 18 Jan 2004 23:51:28 GMT, "Daniel T."

EXACTLY what I was after - thank you so much!

Russ
 
J

Jonathan Turkanis

Martin Eisenberg said:
Ron said:
You're only guaranteed to be able to apply operator[] to
random access iterators.

Does *(it + k) work with all iterators?

No. Here's a good summary of iterator requirements. It's not
authoritative (e.g., "trivial iterators" aren't mentioned in the
standard) but its pretty good.

Jonathan
 

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

No members online now.

Forum statistics

Threads
474,159
Messages
2,570,879
Members
47,416
Latest member
LionelQ387

Latest Threads

Top