4

I have been trying to fill a vector from a map. I know how to do this in a more conventional way, but I was trying to achive it with STL algorithms (a one liner) as some kind of a training :).

the origin map type is :

std::map< std::string, boost::shared_ptr< Element > >

the destination vector is :

std::vector< Element > theVector;

what I have so far is this:

std::transform( theMap.begin(), theMap.end(),
        std::back_inserter( theVector ),
        boost::bind( &map_type::value_type::second_type::get, _1 )
        );

But this is trying to insert a pointer in the vector which doesn't work. I have also tried this:

using namespace boost::lambda;
using boost::lambda::_1;

std::transform( theMap.begin(), theMap.end(),
        std::back_inserter( theVector ),
        boost::bind( &map_type::value_type::second_type::get, *_1 )
        );

But it's not working either.

Edit:

I've got this working solution but I find it less impressive :)

std::for_each( theMap.begin(), theMap.end(), 
        [&](map_type::value_type& pair)
        {
            theVector.push_back( *pair.second );
        } );

Edit2: The thing I'm the less comfortable with here is bind(), so bind() solutions are welcome!

foke
  • 1,339
  • 2
  • 12
  • 20
  • Vector _owns_ it's resources and so does shared_ptr, hence moving without making a copy is out of question here, but I guess you're not necessarily trying to move from the shared_ptr to vector, but just to copy in an elegant way. – legends2k Jan 31 '13 at 16:48

2 Answers2

2

How about:

// Using std::shared_ptr and lambdas as the solution
// you posted used C++11 lambdas.
//
std::map<std::string, std::shared_ptr<Element>> m
    {
        { "hello", std::make_shared<Element>() },
        { "world", std::make_shared<Element>() }
    };
std::vector<Element> v;

std::transform(m.begin(),
               m.end(),
               std::back_inserter(v),
               [](decltype(*m.begin())& p) { return *p.second; });

See online demo at http://ideone.com/ao1C50 .

hmjd
  • 120,187
  • 20
  • 207
  • 252
  • 1
    that's more or less equivalent to my for_each solution. I was looking for a bind() solution, I think it's possible but I may be wrong – foke Jan 31 '13 at 17:09
  • @foke I agree, it's similar to your solution in the question, but I guess you do know that both lambda and bind wouldn't alter the performance and many times `bind` is more readable (http://stackoverflow.com/questions/1930903/bind-vs-lambda) – legends2k Jan 31 '13 at 18:24
1

Another alternative may be the new for syntax:

for(auto &cur_pair: the_map) { theVector.push_back(*(cur_pair.second)); }

It's at least a one-liner (kinda), though it's just another way to do your std::for_each but more compact.

Kevin Anderson
  • 6,850
  • 4
  • 32
  • 54
  • I didn't think about this ;) but I'm using vs 2010 and I believe it does not support this syntax – foke Jan 31 '13 at 17:18
  • You are correct in that it's supported in 2012 but not 2010. See this link for the msdn reference: http://msdn.microsoft.com/en-ca/library/vstudio/hh567368.aspx It's known as the "Range-based for loop" in that listing, and it confirms it's in 2012 but not 2010. – Kevin Anderson Jan 31 '13 at 17:22