[phoenix] or [lamdba] Operating on containers of smart pointers.

I ran into a problem while cleaning up some old code. What I wanted to do was replace explicit for loops with some stl algorithms or BOOST_FOREACH. Below is the original function: |//in header file: ..snip typedef std::vector<Loki::SmartPtr<ADTChunk> > chunk_vec_t chunk_vec_t chunks; ..snip //in source file: uint32_t ADT::get_connectivity_data( std::vector< std::vector<uint8_t> > &output ) { output.resize(chunks.size()); for(chunk_vec_t::iterator it = chunks.begin(); it < chunks.end(); ++it) { uint32_t success = (*it)->get_connectivity_data(output[it-chunks.begin()]); } return TRUE; } I asked on a separate website for some possibilities of replacing this code with boost::lambda, and the following almost correct suggestion was given to replace the loop: ||std::for_each( chunks.begin(), chunks.end(), bind( &chunk_vec_t::value::type::get_connectivity_data, _1, output[ std::distance( _1, chunks.begn() ] ) ); The problem is that the above obviously does not compile, so I made some changes and came up with this: ||std::for_each( chunks.begin(), chunks.end(), bind( &chunk_vec_t::value_type::StoredType::get_connectivity_data, _1, output[ std::distance( &_1, &chunks[0] ) ] ) ); The problem with the above is that "||&chunk_vec_t::value_type::StoredType::get_connectivity_data|" causes the VC9 compiler to crash =( So I made this change: |std::for_each( chunks.begin(), chunks.end(), bind( &ADTChunk::get_connectivity_data, _1, output[ std::distance( _1, chunks.begin() ) ] ) ); But now I get an error with the call to std::distance not being able to discern the arguments due to ambiguity. Next I thought that I might be able to use zip_iterator to assist in dealing with both of the containers, and then I realized it used tuples, which then made me thing that extracting the iterators from the tuples is going to take a lot of boiler plate code itself. Which led me to settle with the following code that is concise and easily readable but will only work if chunks is a vector essentially: BOOST_FOREACH(chunk_vec_t::value_type it, chunks) { output[std::distance(&it, &chunks[0])] = it->get_connectivity_data(); } So, my final question is, given my above attempts, is there a way to do what the 1st and 5th(the one immediately above this line) code snippets do in a straight-forward manner using either boost::lambda, or, since it will be replaced eventually by phoenix v3, with phoenix v2? Thanks! | | |

On Thu, Oct 23, 2008 at 7:21 AM, Raindog <raindog@macrohmasheen.com> wrote:
I ran into a problem while cleaning up some old code. What I wanted to do was replace explicit for loops with some stl algorithms or BOOST_FOREACH. Below is the original function:
|//in header file: ..snip typedef std::vector<Loki::SmartPtr<ADTChunk> > chunk_vec_t chunk_vec_t chunks; ..snip
//in source file: uint32_t ADT::get_connectivity_data( std::vector< std::vector<uint8_t> > &output ) { output.resize(chunks.size()); for(chunk_vec_t::iterator it = chunks.begin(); it < chunks.end(); ++it) { uint32_t success = (*it)->get_connectivity_data(output[it-chunks.begin()]); } return TRUE; }
I asked on a separate website for some possibilities of replacing this code with boost::lambda, and the following almost correct suggestion was given to replace the loop:
||std::for_each( chunks.begin(), chunks.end(), bind( &chunk_vec_t::value::type::get_connectivity_data, _1, output[ std::distance( _1, chunks.begn() ] ) );
The problem is that the above obviously does not compile, so I made some changes and came up with this:
||std::for_each( chunks.begin(), chunks.end(), bind( &chunk_vec_t::value_type::StoredType::get_connectivity_data, _1, output[ std::distance( &_1, &chunks[0] ) ] ) );
The problem with the above is that "||&chunk_vec_t::value_type::StoredType::get_connectivity_data|" causes the VC9 compiler to crash =(
So I made this change:
|std::for_each( chunks.begin(), chunks.end(), bind( &ADTChunk::get_connectivity_data, _1, output[ std::distance( _1, chunks.begin() ) ] ) );
But now I get an error with the call to std::distance not being able to discern the arguments due to ambiguity.
Next I thought that I might be able to use zip_iterator to assist in dealing with both of the containers, and then I realized it used tuples, which then made me thing that extracting the iterators from the tuples is going to take a lot of boiler plate code itself. Which led me to settle with the following code that is concise and easily readable but will only work if chunks is a vector essentially:
BOOST_FOREACH(chunk_vec_t::value_type it, chunks) { output[std::distance(&it, &chunks[0])] = it->get_connectivity_data(); }
So, my final question is, given my above attempts, is there a way to do what the 1st and 5th(the one immediately above this line) code snippets do in a straight-forward manner using either boost::lambda, or, since it will be replaced eventually by phoenix v3, with phoenix v2?
I confess to having only given this a cursory glance over the first coffee of the day, but isn't this essentially a transform operation, for which the transform algorithm would be the clearest solution? Cheers, Rob.

On Thu, Oct 23, 2008 at 8:08 AM, Robert Jones <robertgbjones@gmail.com>wrote:
I confess to having only given this a cursory glance over the first coffee of the day, but isn't this essentially a transform operation, for which the transform algorithm would be the clearest solution?
Please ignore the foregoing - it was total gibberish. - Rob.

My final solution that resulted in the 5th code block was to change get_connectivity_data to return a vector instead of taking one by reference, and that change would more easily allow the usage of transform. The key part of the problem I could not solve was the calling of a member function on each element of the containerwhile passing in a parameter which sounds really easy but for some reason was not Sent from my Verizon Wireless BlackBerry -----Original Message----- From: "Robert Jones" <robertgbjones@gmail.com> Date: Thu, 23 Oct 2008 08:08:38 To: <boost-users@lists.boost.org> Subject: Re: [Boost-users] [phoenix] or [lamdba] Operating on containers of smart pointers. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

AMDG Raindog wrote:
I ran into a problem while cleaning up some old code. What I wanted to do was replace explicit for loops with some stl algorithms or BOOST_FOREACH. Below is the original function:
|//in header file: ..snip typedef std::vector<Loki::SmartPtr<ADTChunk> > chunk_vec_t chunk_vec_t chunks; ..snip
//in source file: uint32_t ADT::get_connectivity_data( std::vector< std::vector<uint8_t>
&output ) { output.resize(chunks.size()); for(chunk_vec_t::iterator it = chunks.begin(); it < chunks.end(); ++it) { uint32_t success = (*it)->get_connectivity_data(output[it-chunks.begin()]); } return TRUE; }
I think what you want is a two argument version of for_each. #include <boost/cstdint.hpp> #include <boost/shared_ptr.hpp> #include <boost/lambda/lambda.hpp> #include <boost/lambda/bind.hpp> #include <vector> typedef std::vector<boost::uint8_t> out_t; struct ADTChunk { boost::uint32_t get_connectivity_data(out_t& output) { return(0); } }; typedef std::vector<boost::shared_ptr<ADTChunk> > chunk_vec_t; chunk_vec_t chunks; template<class Iter1, class Iter2, class F> F for_each(Iter1 begin1, Iter1 end1, Iter2 begin2, F f) { for(; begin1 != end1; ++begin1, ++begin2) { f(*begin1, *begin2); } return(f); } boost::uint32_t get_connectivity_data(std::vector<out_t> &output) { using namespace boost::lambda; output.resize(chunks.size()); for_each(chunks.begin(), chunks.end(), output.begin(), bind(&ADTChunk::get_connectivity_data, *_1, _2)); return 1; } In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Raindog wrote:
I ran into a problem while cleaning up some old code. What I wanted to do was replace explicit for loops with some stl algorithms or BOOST_FOREACH. Below is the original function:
|//in header file: ..snip typedef std::vector<Loki::SmartPtr<ADTChunk> > chunk_vec_t chunk_vec_t chunks; ..snip
//in source file: uint32_t ADT::get_connectivity_data( std::vector< std::vector<uint8_t> > &output ) { output.resize(chunks.size()); for(chunk_vec_t::iterator it = chunks.begin(); it < chunks.end(); ++it) { uint32_t success = (*it)->get_connectivity_data(output[it-chunks.begin()]); } return TRUE; }
I think what you want is a two argument version of for_each.
Thanks Steven, what I did actually instead was make a few modifications to the functions involved and came up with this as a replacement of the explicit for loop. std::transform(chunks.begin(), chunks.end(), back_inserter(tmp), boost::bind(&ADTChunk::get_connectivity_data, _1) );
participants (4)
-
Raindog
-
raindog@macrohmasheen.com
-
Robert Jones
-
Steven Watanabe