Consider the following code, which uses the Ranges library from C++20:
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
std::vector<int> v{0,1,2,3,4,5,6,7};
auto transformed = std::ranges::views::transform(v, [](int i){ return i * i; });
std::cout << *std::prev(std::end(transformed));
}
I was quite surprised to learn that (at least under GCC-10.3.0 and GCC-12.0.0) this code gets stuck in std::prev.
What happens is that since the lambda doesn't return an lvalue reference, the transformed range iterators are classified as input iterators (see the rules for iterator_category selection for views::transform). However, std::prev requires the iterator to be at least a bidirectional iterator, so I guess this code is actually UB. In libstdc++ applying std::prev to an input iterator leads to this function
template<typename _InputIterator, typename _Distance>
__advance(_InputIterator& __i, _Distance __n, input_iterator_tag)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_assert(__n >= 0);
while (__n--)
++__i;
}
being called with __n == -1, which explains the observed behavior.
If we replace std::prev with manual iterator decrement, everything works fine. Switching to std::ranges::prev works, too.
Now, it is clearly nonsensical that I can't do std::prev on what is just a view over an std::vector. While a simple solution exists, I feel extremely worried about this unexpected interplay between old and new range manipulation parts of the standard library. So, my question is: is this a known problem, and should I really forget everything not in the std::ranges namespace when working with the new ranges, and rewrite all the existing code to make sure they work with the new ranges?
std::prevrequires a bidirectional iterator or not: cplusplus.github.io/LWG/issue3197std::prevto work with C++20 bidirectional iterators which don't meet Cpp17BidirectionalIterator reqs. The prototype patch at gcc.gnu.org/pipermail/gcc-patches/2025-July/689975.html fixes yourtransformexample so it works.