Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

selecting a single member from each structure in a std::vector into another vector

Tags:

c++

stl

I have a Visual Studio 2008 C++ project where I would like to copy one struct element of a vector of that struct type to a new vector. For example:

struct Foo {
    int a;
    long b;
};

std::vector< Foo > v1;
std::vector< long > v2;

for( std::vector< Foo >::const_iterator it = v1.begin(); it != v1.end(); ++it )
{
    v2.push_back( it->b );
}

Is there a better/more elegant way than this?

Thanks, PaulH

like image 352
PaulH Avatar asked Mar 29 '12 21:03

PaulH


2 Answers

In Visual C++ 2008, no, this is about as "elegant" as it gets. The Standard Library provides algorithms that can be used to manipulate containers, but in most scenarios--especially in simple use cases like this one--they are far too cumbersome to use.

C++11 adds lambda expressions to C++. Visual C++ 2010 and recent versions of other C++ compilers support this C++11 feature. With lambda expressions, you can easily use the transform algorithm for your task:

std::transform(v1.begin(), v1.end(), std::back_inserter(v2),
               [](Foo const& x) { return x.b; });

Without lambda expressions, you'd have to define a function to extract the b element from the struct:

long get_b(Foo const& x) { return x.b; }

You could then use this function with the transform algorithm:

std::transform(v1.begin(), v1.end(), std::back_inserter(v2), get_b);

However, for simple use cases like this, this can quickly lead to unwieldy code as it is difficult to neatly keep all of the related functions together.

like image 118
James McNellis Avatar answered Oct 23 '22 04:10

James McNellis


It really depends on what you mean with "better".

If you mean if the same can be written by using template trickery then the answer is yes:

template<typename C, typename T>
struct MemberGetter
{
    T C::*mp;
    MemberGetter(T C::*mp) : mp(mp) { }
    T operator()(const C& c) { return c.*mp; }
};

struct Foo
{
    double dm;
};

...
std::vector<double> x;
std::vector<Foo> y;

std::transform(y.begin(), y.end(),
               std::back_inserter(x),
               MemberGetter<Foo, double>(&Foo::dm));

This is in my opinion worse than an explicit loop, but has the advantage that the member pointer (i.e. which part of the structure you are copying) can be a runtime parameter.

If the member you need to copy is instead known and fixed then I'd say that the explicit loop is the best way (I can barely imagine corner cases in which using a similar template where the member pointer is a template parameter makes any sense).

like image 33
6502 Avatar answered Oct 23 '22 06:10

6502