从std :: vector中的每个结构中选择一个成员到另一个向量中

时间:2012-03-29 21:09:01

标签: c++ stl

我有一个Visual Studio 2008 C ++项目,我希望将该结构类型的向量的一个struct元素复制到一个新向量。例如:

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

有比这更好/更优雅的方式吗?

谢谢,  PaulH

2 个答案:

答案 0 :(得分:18)

在Visual C ++ 2008中,不,这就像它所获得的那样“优雅”。标准库提供了可用于操作容器的算法,但在大多数情况下 - 特别是在像这样的简单用例中 - 它们使用起来太麻烦了。

C ++ 11将lambda表达式添加到C ++中。 Visual C ++ 2010和其他C ++编译器的最新版本支持此C ++ 11功能。使用lambda表达式,您可以轻松地将transform算法用于您的任务:

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

如果没有lambda表达式,则必须定义一个函数来从结构中提取b元素:

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

然后,您可以将此函数与transform算法一起使用:

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

但是,对于这样的简单用例,这很快就会导致代码难以处理,因为很难将所有相关功能整齐地保存在一起。

答案 1 :(得分:1)

这实际上取决于你对“更好”的意思。

如果你的意思是如果使用模板技巧可以写同样的话,那么答案是肯定的:

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

在我看来,这比显式循环更糟糕,但其优点是成员指针(即您正在复制的结构的哪一部分)可以是运行时参数。

如果您需要复制的成员是已知并修复的,那么我会说显式循环是最好的方法(我几乎无法想象使用类似模板的情况,其中成员指针是模板参数使任何意义上的。)