Reputation: 13135
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.
Upvotes: 3
Views: 201
Reputation: 208353
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));
Upvotes: 6
Reputation: 5887
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.
Upvotes: 2
Reputation: 3413
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));
Upvotes: 4
Reputation: 31655
Use std::transform
. This takes care of the actual copying in one line. You will have to write a transformation function, though.
Upvotes: 4