Все ответы, представленные до настоящего времени, в конечном итоге создают std::set
напрямую, что может быть не идеальным: если вы хотите иметь возможность только перебирать ключи, вам не нужны дополнительные затраты на создание Весь новый контейнер.
Более гибким вариантом будет использование итератора преобразования, который преобразует итератор std::map
в некоторый тип итератора, который просто возвращает ключ при разыменовании. Это довольно просто, используя Boost Transform Iterator:
#include <functional>
#include <boost/iterator/transform_iterator.hpp>
// You may already have a select1st implementation; if not, you should :-)
template <typename Pair>
struct select1st
: std::unary_function<const Pair&, const typename Pair::first_type&>
{
const typename Pair::first_type& operator()(const Pair& p) const
{
return p.first;
}
};
template <typename C>
boost::transform_iterator<
select1st<typename C::value_type>, typename C::const_iterator
> begin_keys(const C& c)
{
return boost::make_transform_iterator(
c.begin(), select1st<typename C::value_type>()
);
}
template <typename C>
boost::transform_iterator<
select1st<typename C::value_type>, typename C::const_iterator
> end_keys(const C& c)
{
return boost::make_transform_iterator(
c.end(), select1st<typename C::value_type>()
);
}
С помощью этих служебных функций вы можете преобразовать любой диапазон std::map
итераторов (или итераторов в любой другой парный ассоциативный контейнер, который вы можете иметь) в диапазон только ключей. Как пример:
#include <iostream>
#include <iterator>
#include <map>
int main()
{
std::map<int, int> m;
m.insert(std::make_pair(1, 2));
m.insert(std::make_pair(2, 4));
m.insert(std::make_pair(3, 6));
std::copy(
begin_keys(m), end_keys(m),
std::ostream_iterator<int>(std::cout, ","));
}
Эта программа выводит:
1,2,3,
Если вы действительно хотите std::set
, содержащий ключи, вы можете легко создать его, используя следующие итераторы:
std::set<int> s(begin_keys(m), end_keys(m));
В целом, это более гибкое решение.
Если у вас нет Boost или вы не хотите использовать Boost или не можете использовать Boost, этот конкретный итератор преобразования можно реализовать довольно легко:
#include <iterator>
template <typename C>
class key_iterator
: public std::iterator<
std::bidirectional_iterator_tag,
typename C::key_type,
typename C::difference_type,
typename C::pointer,
typename C::reference
>
{
public:
key_iterator() { }
explicit key_iterator(typename C::const_iterator it) : it_(it) { }
typename const C::key_type& operator*() const { return it_->first; }
typename const C::key_type* operator->() const { return &it_->first; }
key_iterator& operator++() { ++it_; return *this; }
key_iterator operator++(int) { key_iterator it(*this); ++*this; return it; }
key_iterator& operator--() { --it_; return *this; }
key_iterator operator--(int) { key_iterator it(*this); --*this; return it; }
friend bool operator==(const key_iterator& lhs, const key_iterator& rhs)
{
return lhs.it_ == rhs.it_;
}
friend bool operator!=(const key_iterator& lhs, const key_iterator& rhs)
{
return !(lhs == rhs);
}
private:
typename C::const_iterator it_;
};
template <typename C>
key_iterator<C> begin_keys(const C& c) { return key_iterator<C>(c.begin()); }
template <typename C>
key_iterator<C> end_keys(const C& c) { return key_iterator<C>(c.end()); }
Использование для этого такое же, как и для версии Boost.