Используйте STL для заполнения вектора <T> с помощью карт <T, Z>

map<T,Z> m= ...;
vector<T> v;
v.reserve(m.size);
for(map<T,Z>::iterator it=m.begin();it!=m.end();++it)
{
 v.push_back(it->first);
}

Есть ли более приятная 1-строчная версия, использующая некоторые функции STL?

изменить: не использовать С++ 11!

Ответ 1

Портативный:

struct SelectKey {
  template <typename F, typename S>
  F operator()(const std::pair<const F, S> &x) const { return x.first; }
};

std::transform(m.cbegin(), m.cend(), std::back_inserter(v), SelectKey());

Я думаю, что некоторые реализации STL имеют нестандартное расширение, называемое select1st, что эквивалентно показателю SelectKey, показанному здесь. Как отметил K-Ballo в комментариях, есть также версия TR1. Мне нравится явно названная версия, так как легче видеть, что происходит.

Поскольку нет необходимости в состоянии, вы можете уйти со слегка меньшим количеством шаблонов, используя фактическую функцию, а не функтор:

template <typename F, typename S>
F SelectKey()(const std::pair<const F, S> &x) { return x.first; }

std::transform(m.cbegin(), m.cend(), std::back_inserter(v), SelectKey);

Если вы можете использовать С++ 11, вы можете использовать лямбду, которая держит код выбора близко к тому, где он используется:

std::transform(m.cbegin(), m.cend(), std::back_inserter(v),
               [](const std::pair<const F, S> &x) { return x.first; });

или даже на основе диапазона для цикла, который, вероятно, наиболее изящный и читаемый:

for(const auto &x : m) {
  v.push_back(x.first);
}

Ответ 2

Pre С++ 11, вы можете использовать преобразование и настраиваемую функцию struct:

template <class K, class V>
struct key_selector : std::unary_function<const std::pair<K, V>&, const K&>
{
    const K& operator()(const std::pair<K, V>& element) const
    {
        return element.first;
    }
};

transform(m.begin(), m.end(), back_inserter(v), key_selector<T,Z>());

Если у вас есть доступ к boost или TR1, вы можете заменить key_selector на mem_fn

transform(m.begin(), m.end(), back_inserter(v), mem_fn(&map<T,Z>::value_type::first));

Post-С++ 11, вы можете использовать lambdas:

transform(m.begin(), m.end(), back_inserter(v), [](const map<T,Z>::value_type& x) {return x.first;});

Ответ 3

В С++ 11 вы можете использовать лямбда-выражения:

typedef std::map< std::string, std::string > map_t;
map_t map;
std::vector< std::string > v;

std::for_each(map.begin(), map.end(), [&v](map_t::value_type const& it)
        {
            v.push_back(it.first);
        });

Ответ 4

Вы можете сделать что-то по строкам:

std::transform(m.begin(), m.end(), std::back_inserter(v), FUNCTOR);

Где FUNCTOR зависит от версии STL или библиотек и компиляторов, которые у вас есть.

С++ 11 (lambda)

std::transform(m.begin(), m.end(), std::back_inserter(v), [](map<T,Z>::const_reference a) { return a.first; });

С++ 11 (std:: get)

std::transform(m.begin(), m.end(), std::back_inserter(v), &std::get<0>);

С++ SGI STL имеет функтор, называемый select1st, который можно использовать

std::transform(m.begin(), m.end(), std::back_inserter(v), select1st);

С++ 03 (Not С++ 11), используя объект-функтор, как описано другими людьми.