Подтвердить что ты не робот

Выбор одного элемента из каждой структуры в std::vector в другой вектор

У меня есть проект Visual Studio 2008 С++, где я хотел бы скопировать один элемент структуры вектора этого типа структуры в новый вектор. Например:

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

4b9b3361

Ответ 1

В Visual С++ 2008 нет, это примерно так же "элегантно", как и получается. Стандартная библиотека предоставляет алгоритмы, которые можно использовать для манипулирования контейнерами, но в большинстве сценариев - особенно в простых случаях использования, подобных этой, - они слишком громоздки для использования.

С++ 11 добавляет лямбда-выражения в С++. Visual С++ 2010 и последние версии других компиляторов С++ поддерживают эту функцию С++ 11. С помощью лямбда-выражений вы можете легко использовать алгоритм transform для своей задачи:

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

Без лямбда-выражений вам нужно будет определить функцию для извлечения элемента b из структуры:

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

Затем вы можете использовать эту функцию с помощью алгоритма transform:

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

Однако, для простых случаев использования, подобных этому, это может быстро привести к громоздкому коду, так как трудно аккуратно сохранить все связанные функции.

Ответ 2

Это действительно зависит от того, что вы подразумеваете под "лучше".

Если вы имеете в виду, что то же самое можно написать, используя шаблонную обманку, тогда да:

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

Это, на мой взгляд, хуже, чем явный цикл, но имеет то преимущество, что указатель-член (т.е. какая часть структуры, которую вы копируете) может быть параметром времени выполнения.

Если член, который вам нужно скопировать, будет известен и исправлен, тогда я бы сказал, что явный цикл является лучшим способом (я едва могу представить себе угловые случаи, в которых с использованием аналогичного шаблона, где указатель-член является параметром шаблона, любой смысл).