Written by
Niels Moseley
on
on
C++20 std::map iterators with key or value access
Sometimes you want to iterate only the keys or values of a std::map
or std::unordered_map
. The AccessIterator
allows just that, avoiding use of the less-than-transparent std::pair<>
. It also handles const and non-const containers automatically.
Iterator code
/*
Copyright Niels Moseley, 2024
SPDX-License-Identifier: LSC
*/
#pragma once
#include <iterator>
namespace MapIterators
{
/** Iterator for std::map and std::unordered_map, both const and non-const
with Accessor callable that returns an item form the container
*/
template<typename Accessor, typename Container>
struct AccessIterator
{
using ContainerType = typename std::remove_reference_t<Container>;
AccessIterator(Container &container) : m_container(container) {}
auto begin()
{
return IteratorWrapper(m_container.begin());
}
auto end()
{
return IteratorWrapper(m_container.end());
}
ContainerType &m_container;
template<typename It>
struct IteratorWrapper
{
IteratorWrapper(It iter) : m_iter(iter) {}
constexpr auto operator++()
{
return ++m_iter;
}
constexpr auto operator++(int)
{
return m_iter++;
}
auto& operator*()
{
return m_accessor(*m_iter);
}
constexpr bool operator==(const IteratorWrapper &other) noexcept
{
return m_iter == other.m_iter;
}
constexpr bool operator!=(const IteratorWrapper &other) noexcept
{
return m_iter != other.m_iter;
}
Accessor m_accessor;
It m_iter;
};
};
struct KeyAccessor
{
auto& operator()(auto &v)
{
return v.first;
}
};
struct ValueAccessor
{
auto& operator()(auto &v)
{
return v.second;
}
};
constexpr auto keys(auto &MapContainer)
{
return MapIterators::AccessIterator<KeyAccessor, decltype(MapContainer)>(MapContainer);
}
constexpr auto values(auto &MapContainer)
{
return MapIterators::AccessIterator<ValueAccessor, decltype(MapContainer)>(MapContainer);
}
};
Usage
std::map<std::size_t, std::string> myMap;
myMap[0] = "Testing123";
myMap[1] = "Hello, world!";
myMap[99] = "Luftballons";
for(auto key : MapIterators::keys(myMap))
{
std::cout << "key: " << key << "\n";
}
for(auto &value : MapIterators::values(myMap))
{
std::cout << "value: " << value << "\n";
}