Я собираюсь сначала ответить на это в c ++ 14 .
Вот минимальный итератор отображения:
template<class F, class It>
struct iterator_mapped {
decltype(auto) operator*() const {
return f(*it);
}
iterator_mapped( F f_in, It it_in ):
f(std::move(f_in)),
it(std::move(it_in))
{}
iterator_mapped( iterator_mapped const& ) = default;
iterator_mapped( iterator_mapped && ) = default;
iterator_mapped& operator=( iterator_mapped const& ) = default;
iterator_mapped& operator=( iterator_mapped && ) = default;
iterator_mapped& operator++() {
++it;
return *this;
}
iterator_mapped operator++(int) {
auto copy = *this;
++*this;
return copy;
}
friend bool operator==( iterator_mapped const& lhs, iterator_mapped const& rhs ) {
return lhs.it == rhs.it;
}
friend bool operator!=( iterator_mapped const& lhs, iterator_mapped const& rhs ) {
return !(lhs==rhs);
}
private:
F f;
It it;
};
технически это не итератор, но он подходит для for(:)
циклов.
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
};
template<class It>
range_t<It> range( It b, It e ) {
return {std::move(b), std::move(e)};
}
Выше приведен абсолютно минимальный тип диапазона итератора, который может быть for(:)
повторен.
template<class F, class R>
auto map_range( F&& f, R& r ) {
using std::begin; using std::end;
auto b = begin(r);
auto e = end(r);
using it = iterator_mapped<std::decay_t<F>, decltype(b)>;
return range( it( f, b ), it( f, e ) );
}
обратите внимание, что R&
не R&&
; принимать значение для r
здесь опасно.
auto GetStringIterator() const
{
return map_range( [](auto&& pair)->decltype(auto){
return pair.second;
}, m_Items );
}
и готово.
Преобразование этого в c ++ 11 - это боль. Вы должны бросить около 1026 * s вместо лямбды (или написать функциональные объекты, которые выполняют задачу вместо лямбды), заменить decltype(auto)
на auto
и конечные типы возврата, дать точный тип auto&&
аргументов к лямбдам и т. д. В итоге у вас появляется на 25% -50% больше кода, большая часть которого скрывает погоню за типом.
Это в основном то, что делает boost::adaptors::map_values
, но это происходит вручную, так что вы можете понять, как это работает, и не иметь буст-зависимости.