Domanda

struct Node
{
    std::string name;
    ...
};

typedef std::vector<Node> Nodes;

Nodes nodes;
std::vector<std::string> names;

Is there a nice one-liner way of populating the vector names with Node::name for each item in nodes?

This is what I currently do:

names.reserve(nodes.size());
BOOST_FOREACH(Node node, nodes) 
{
    names.push_back(node.name);
}

I'm using C++98, std and boost.

È stato utile?

Soluzione

This is much simpler with newer libraries (boost) and or standards (C++11), but you should be able to write a small functor:

struct ReadNodeName {
   std::string const & operator()(Node const & node) const {
      return node.name;
   }
};

And then use std::transform

std::transform(nodes.begin(), nodes.end(),
               std::back_inserter(names),
               ReadNodeName());

With boost, the functor could be just boost::bind, in C++11 you could use a lambda: [](Node const & node) { return node.name; };, in C++14 a shorter lambda [](auto& n) { return n.name; }:

std::transform(nodes.begin(), nodes.end(),
               std::back_inserter(names),
               [](auto & n){return n.name;});

Using boost bind -- beware, untested, I don't have access to boost

std::transform(nodes.begin(), nodes.end(),
               std::back_inserter(names),
               boost::bind(&Node::name, _1));

Altri suggerimenti

Use std::transform. This takes care of the actual copying in one line. You will have to write a transformation function, though.

If you add a getName() function to Node, you can do this:

std::transform(nodes.begin(), nodes.end(), back_inserter(names), mem_fun(&Node::getName));

Since you mention boost, here is one liner with boost::lambda:

std::transform(nodes.begin(),nodes.end(), std::back_inserter(names), &boost::lambda::_1 ->* &Node::name );

Boost lambda cannot overload .* so first we need to get address &, and then use ->* to get reference to member.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top