I want to have the following work
std::vector<int> range{0,1,2,3};
for(std::vector<int>::iterator vit : range | iterator_range ){
int v = *vit;
}
this would be equivalent to the standard for loop
std::vector<int> range{0,1,2,3};
for(std::vector<int>::iterator vit = begin(range); vit !=end(range); vit++) ){
int v = *vit;
}
except more elegant.
iterator_range
is an adapter that I require.
I have some algorithms where it is useful to require to have an iterator to the element inside the loop rather than the element itself.
Note that views::iota
is not limited to integers, it's anything that's incrementable and comparable. Which includes iterators!
inline constexpr auto iterators_of = []<ranges::range R>(R&& r){
static_assert(ranges::borrowed_range<R>);
return views::iota(ranges::begin(r), ranges::end(r));
};
This at least gets you started, and maybe is good enough. Ideally you have a proper range adapter that captures views::all(r)
without requiring borrowed, and actually gives out these iterators directly.
A more complete implementation (if actually necessary) would be:
template <std::ranges::view V>
struct iterators_for_view : std::ranges::view_interface<iterators_for_view<V>> {
V view;
template <class R>
using iota_for = std::ranges::iota_view<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>>;
explicit iterators_for_view(V v) : view(std::move(v)) { }
auto begin() { return std::ranges::iterator_t<iota_for<V>>(std::ranges::begin(view)); }
auto end() { return std::ranges::sentinel_t<iota_for<V>>(std::ranges::end(view)); }
auto begin() const requires std::ranges::range<V const> { return std::ranges::iterator_t<iota_for<V const>>(std::ranges::begin(view)); }
auto end() const requires std::ranges::range<V const> { return std::ranges::sentinel_t<iota_for<V const>>(std::ranges::end(view)); }
auto size() requires std::ranges::sized_range<V> { return std::ranges::size(view); }
auto size() const requires std::ranges::sized_range<V const> { return std::ranges::size(view); }
};
struct iterators_for_fn : std::ranges::range_adaptor_closure<iterators_for_fn> {
template <std::ranges::viewable_range R>
constexpr auto operator()(R&& r) const {
return iterators_for_view(std::views::all((R&&)r));
}
};
inline constexpr iterators_for_fn iterators_for{};
Which you can see here.