I'm trying to familiarize with the ranges-v3
library, that will be part of the C++20 standard. To do so, I'm trying to refactor some toy code by replacing (where suitable) classic iterators and algorithms with the new available constructs. In this particular example, I can't figure out how to pass the returned iterator of a call to ranges::min_element
(which replaced a call to std::min_element
) to another function of mine which accepts a classic iterator
as parameter.
I've searched inside the documentation of the library looking for some sort of functions like smartIt2classicIt
with no success.
Here is a minimal example
void f(std::vector<int>& v, std::vector<int>::iterator it); // old function that I want to reuse
auto predicate = [](int i){ return true; }; // check function
std::vector<int> v;
// auto min_el = std::min_element(...); // old code
auto filtered_range = v | ranges::view::filter(predicate); // to avoid a dangling iterator
auto min_el = ranges::min_element(filtered_range);
f(v, min_el); // pass min_el to f: doesn't compile with the new code
At first I expected that the result of ranges::min_element
was implicitly convertible to a classic iterator, but I was wrong: the compiler returns a long error saying that cannot convert a ranges::basic_iterator bla bla bla to a std::vector bla bla bla iterator
. Given this error I deduce that ranges::min_element
indeed returns some sort of iterator, but how to use it the old way?
I see three possible solutions:
min_el
is passed to f
f
(possibly in a backward-compatible way)but I can't figure out how to implement any of them. Maybe there is another solution? I also see another possible source of troubles, since the returned iterator probably refers to filtered_range
instead of v
... Any help is welcome!
Iterator: a pointer-like object that can be incremented with ++, dereferenced with *, and compared against another iterator with != . Iterators are generated by STL container member functions, such as begin() and end().
Generally, like this: struct vec{ iterator begin() ; const_iterator begin() const; };
Operator= -- Assign the iterator to a new position (typically the start or end of the container's elements). To assign the value of the element the iterator is pointing at, dereference the iterator first, then use the assign operator.
An iterator is used to point to the memory address of the STL container classes. For better understanding, you can relate them with a pointer, to some extent. Iterators act as a bridge that connects algorithms to STL containers and allows the modifications of the data present inside the container.
You can convert an adapted iterator to its base iterator via the base()
member function.
For example:
std::vector<int>::const_iterator foo(std::vector<int> const& v) {
auto filtered = v | ranges::view::filter([](int i){return i > 5;});
auto min_el = ranges::min_element(filtered);
return min_el.base();
}
Note that this only removes one layer of wrapping, it doesn't drop to the bottom. So if you had another adapter then you'd need another base()
:
std::vector<int>::const_iterator foo(std::vector<int> const& v) {
auto filtered = v | ranges::view::filter([](int i){return i > 5;})
| ranges::view::transform([](int i){ return i * i; });
auto min_el = ranges::min_element(filtered);
return min_el.base().base();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With