выбор одного члена из каждой структуры в std :: vector в другой вектор - PullRequest
13 голосов
/ 30 марта 2012

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

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 ]

18 голосов
/ 30 марта 2012

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

C ++ 11 добавляет лямбда-выражения в C ++. Visual C ++ 2010 и последние версии других компиляторов C ++ поддерживают эту функцию C ++ 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);

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

1 голос
/ 30 марта 2012

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...