polymorphic container/boost::any

I'm quite sure that this problem has been addressed many times before, so I suspect it as a better name and I suspect that boost::any could be the solution. I want to store related types in the same stl container, for instance, this is the class heirachy I want: class tree { public: void grow() =0; }; class oak : public tree { public: void grow() { std::cout << "oak grows slowly" << std::endl; }; class pine : public tree { public: void grow() { std::cout << "pine grows quickly" << std::endl; }; Then, I try to put them in a std::list: std::list< tree > forest; forest.push_back(oak()); forest.push_back(pine()); ...and I find out that I can't define tree::grow as abstract. So I give it a dummy implentation -- void grow() { std::cout << "tree grows" << std::endl; --, and try to iterate over the objects: for(std::list< tree >::iterator iter = forest.begin(); forest.end() != iter; ++iter) { iter->grow(); } ...and I don't get what I expect: tree grows tree grows I then think about trying to use a std::list< tree& > and discover that it won't compile. I think briefly consider std::list< tree* > but decide this dosen't meet requirements of memory management. So I do some searching for 'polymorphic container' and 'polymorphic iterator' and come up with boost::any, but I've no luck in making it work. Attached is my code. In the end, I'm looking for a way to add related types to a stl container and not have to do anything complicated to call a method on the type's abstract interface and to not have to wory about memory management. Maybe this question is better suited for comp.lang.c++[.moderated]? -- Matthew Peltzer -- goochrules@gmail.com

std::list<boost::shared_ptr<tree> > forest; of course you'll have to allocate (new) them before putting their pointers in the list, but that's not a huge issue. At Thursday 2004-08-12 14:01, you wrote:
I'm quite sure that this problem has been addressed many times before, so I suspect it as a better name and I suspect that boost::any could be the solution.
I want to store related types in the same stl container, for instance, this is the class heirachy I want:
class tree { public: void grow() =0; }; class oak : public tree { public: void grow() { std::cout << "oak grows slowly" << std::endl; }; class pine : public tree { public: void grow() { std::cout << "pine grows quickly" << std::endl; };
Then, I try to put them in a std::list:
std::list< tree > forest; forest.push_back(oak()); forest.push_back(pine());
....and I find out that I can't define tree::grow as abstract. So I give it a dummy implentation -- void grow() { std::cout << "tree grows" << std::endl; --, and try to iterate over the objects:
for(std::list< tree >::iterator iter = forest.begin(); forest.end() != iter; ++iter) { iter->grow(); }
....and I don't get what I expect: tree grows tree grows
I then think about trying to use a std::list< tree& > and discover that it won't compile. I think briefly consider std::list< tree* > but decide this dosen't meet requirements of memory management.
So I do some searching for 'polymorphic container' and 'polymorphic iterator' and come up with boost::any, but I've no luck in making it work. Attached is my code.
In the end, I'm looking for a way to add related types to a stl container and not have to do anything complicated to call a method on the type's abstract interface and to not have to wory about memory management. Maybe this question is better suited for comp.lang.c++[.moderated]?
-- Matthew Peltzer -- goochrules@gmail.com
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"

On Fri, 13 Aug 2004 01:52:05 -0700, Victor A. Wagner Jr. <vawjr@rudbek.com> wrote:
std::list<boost::shared_ptr<tree> > forest; of course you'll have to allocate (new) them before putting their pointers in the list, but that's not a huge issue.
Not at all, so long as I use explicit temopries when calling new as the docs say. I've found I also have to change "iter->grow();" to "(*iter)->grow();", but I think i've found a mechanism to solve this. I create a wrapper around the iterator whose operator* and operator-> returns a value_type& (i.e., *iter). The modified code is attached, any suggestions? -- Matthew Peltzer -- goochrules@gmail.com

goochrules! wrote:
On Fri, 13 Aug 2004 01:52:05 -0700, Victor A. Wagner Jr. <vawjr@rudbek.com> wrote:
std::list<boost::shared_ptr<tree> > forest; of course you'll have to allocate (new) them before putting their pointers in the list, but that's not a huge issue.
Not at all, so long as I use explicit temopries when calling new as the docs say.
I've found I also have to change "iter->grow();" to "(*iter)->grow();", but I think i've found a mechanism to solve this. I create a wrapper around the iterator whose operator* and operator-> returns a value_type& (i.e., *iter). The modified code is attached, any suggestions?
You can also use mem_fn: for_each( forest.begin(), forest.end(), mem_fn(&tree::grow) ); or bind, if grow takes arguments: for_each( forest.begin(), forest.end(), bind(&tree::grow, _1, 5) );

"Peter Dimov" <pdimov@mmltd.net> writes:
goochrules! wrote:
On Fri, 13 Aug 2004 01:52:05 -0700, Victor A. Wagner Jr. <vawjr@rudbek.com> wrote:
std::list<boost::shared_ptr<tree> > forest; of course you'll have to allocate (new) them before putting their pointers in the list, but that's not a huge issue. Not at all, so long as I use explicit temopries when calling new as the docs say. I've found I also have to change "iter->grow();" to "(*iter)->grow();", but I think i've found a mechanism to solve this. I create a wrapper around the iterator whose operator* and operator-> returns a value_type& (i.e., *iter). The modified code is attached, any suggestions?
You can also use mem_fn:
for_each( forest.begin(), forest.end(), mem_fn(&tree::grow) );
or bind, if grow takes arguments:
for_each( forest.begin(), forest.end(), bind(&tree::grow, _1, 5) );
And, BTW, your iterator is not conforming and doesn't seem to be doing what you want. See http://www.boost.org/libs/iterator/doc/indirect_iterator.html for a conforming solution. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

You can also use mem_fn:
for_each( forest.begin(), forest.end(), mem_fn(&tree::grow) );
or bind, if grow takes arguments:
for_each( forest.begin(), forest.end(), bind(&tree::grow, _1, 5) );
And, BTW, your iterator is not conforming and doesn't seem to be doing what you want. See http://www.boost.org/libs/iterator/doc/indirect_iterator.html for a conforming solution.
Indeed, boost::shared_ptr and boost::idirect_iterator are exactly what I'm looking for. But I'm at a complete loss as to how to get them to work with std::for_each: 36: typedef boost::shared_ptr< tree > item_t; 37: typedef std::list< item_t > list_t; 38: typedef std::list< item_t >::iterator iter_t; 39: list_t forest; 40: 41: forest.push_back(item_t(new oak)); 42: forest.push_back(item_t(new pine)); 43: 44: boost::indirect_iterator< iter_t, tree > first(forest.begin()), 45: last(forest.end()); 46: std::for_each(first, last, std::mem_fun(&tree::grow));
g++ -Wall -O0 -o inherit inherit.cpp /usr/include/gcc/darwin/3.3/c++/bits/stl_algo.h: In function `_Function std::for_each(_InputIter, _InputIter, _Function) [with _InputIter = boost::indirect_iterator<main(int, char**)::iter_t, tree, boost::use_default, boost::use_default, boost::use_default>, _Function = std::mem_fun_t<void, tree>]': inherit.cpp:46: instantiated from here /usr/include/gcc/darwin/3.3/c++/bits/stl_algo.h:166: error: no match for call to `(std::mem_fun_t<void, tree>) (tree&)' /usr/include/gcc/darwin/3.3/c++/bits/stl_function.h:613: error: candidates are: void std::mem_fun_t<void, _Tp>::operator()(_Tp*) const [with _Tp = tree]
-- Matthew Peltzer -- goochrules@gmail.com

goochrules! <goochrules@gmail.com> writes:
You can also use mem_fn:
for_each( forest.begin(), forest.end(), mem_fn(&tree::grow) );
or bind, if grow takes arguments:
for_each( forest.begin(), forest.end(), bind(&tree::grow, _1, 5) );
And, BTW, your iterator is not conforming and doesn't seem to be doing what you want. See http://www.boost.org/libs/iterator/doc/indirect_iterator.html for a conforming solution.
Indeed, boost::shared_ptr and boost::idirect_iterator are exactly what I'm looking for.
But I'm at a complete loss as to how to get them to work with std::for_each:
36: typedef boost::shared_ptr< tree > item_t; 37: typedef std::list< item_t > list_t; 38: typedef std::list< item_t >::iterator iter_t; 39: list_t forest; 40: 41: forest.push_back(item_t(new oak)); 42: forest.push_back(item_t(new pine)); 43: 44: boost::indirect_iterator< iter_t, tree > first(forest.begin()), 45: last(forest.end()); 46: std::for_each(first, last, std::mem_fun(&tree::grow));
g++ -Wall -O0 -o inherit inherit.cpp /usr/include/gcc/darwin/3.3/c++/bits/stl_algo.h: In function `_Function std::for_each(_InputIter, _InputIter, _Function) [with _InputIter = boost::indirect_iterator<main(int, char**)::iter_t, tree, boost::use_default, boost::use_default, boost::use_default>, _Function = std::mem_fun_t<void, tree>]': inherit.cpp:46: instantiated from here /usr/include/gcc/darwin/3.3/c++/bits/stl_algo.h:166: error: no match for call to `(std::mem_fun_t<void, tree>) (tree&)' /usr/include/gcc/darwin/3.3/c++/bits/stl_function.h:613: error: candidates are: void std::mem_fun_t<void, _Tp>::operator()(_Tp*) const [with _Tp = tree]
Use boost::mem_fn instead. I think you don't even need indirect_iterator in that case... but if you want to keep using indirect_iterator, I think std::mem_fun_ref is what you're after. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (4)
-
David Abrahams
-
goochrules!
-
Peter Dimov
-
Victor A. Wagner Jr.