Search code examples
c++boost-lambdaboost-phoenix

boost lambda or phoenix problem: using std::for_each to operate on each element of a container


I ran into a problem while cleaning up some old code. This is the function:

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

What i am interested in doing is cleaning up the for loop to be a lambda expression but quickly got stuck on how exactly I would pass the correct argument to get_connectivity_data. get_connectivity_data takes a std::vector by reference and fills it with some data. output contains a std::vector for each "chunk".

Basically my conclusion for this was that it was substantially easier, cleaner and shorter to leave my code as-is.

EDIT:

So the closest answer to my question as I envisioned it would look was this:

 std::for_each( chunks.begin(), chunks.end(), 
                   bind( &chunk_vec_t::value::type::get_connectivity_data, 
                         _1, 
                         output[ std::distance( _1, chunks.begn() ] 
                       )
                 );

Yet that code does not compile, I made some modifications to the code to get it to compile but I ran into 2 issues:

  1. _ 1 is a smart ptr, and std::distance did not work on it, I think i needed to use &chunks[0] as the start
  2. Since _ 1 is a smart pointer, I had to do: &chunk_vec_t::value_ type::ValueType::get_ connectivity_ data which caused a crash in the VC9 compiler...

The answer regarding zip_ iterators looked good until i read more into it and discovered that for this particular use, the amount of extra code needed was substantial (binding this and that, etc).

EDIT2:

I found an acceptable solution that is both low on extraneous syntax and clear, which I've posted here and below.

std::transform(chunks.begin(), chunks.end(), back_inserter(tmp), boost::bind(&ADTChunk::get_connectivity_data, _1) );

Solution

  • After a bit of work I came up with this solution:

    std::transform(chunks.begin(), chunks.end(), back_inserter(tmp), boost::bind(&ADTChunk::get_connectivity_data, _1) );
    

    It required that I change get_connectivity_data to return std::vector instead of taking one by reference, and it also required that I change the elements of chunks to be boost::shared_ptr instead of Loki::SmartPtr.