Consider the following example:
int main()
{
std::string_view foo = "This is a test";
auto split_foo = foo |
std::views::split(' ') |
std::ranges::views::transform(
[]( const auto &word )
{
return std::string_view{std::begin(word),std::end(word)};
} );
auto it = std::begin(split_foo);
while (it != std::end(split_foo))
{
std::cout<< "-> " << *it <<std::endl;
it = std::next(it);
}
}
That produces the following output:
-> This
-> is
-> a
-> test
I would like to iterate until one-before-end, such that the output is:
-> This
-> is
-> a
According to the following reference from std::ranges::prev
... for some underlying ranges, ranges::transform_view::end doesn't have the same return type as ranges::transform_view::begin, and so --r.end() won't compile. This isn't something that ranges::prev can aid with, but there are workarounds.
Does anyone know a workaround to decrement the end iterator from std::ranges::views::transform
?
ps. I have tried std::next(std::end(split_foo), -1)
, which compiles but crashes the program because the iterator is not bidirectional.
CodePudding user response:
Just change the while
-loop to:
auto it = split_foo.begin();
auto next = std::ranges::next(it);
while (next != split_foo.end()) {
std::cout<< "-> " << *it <<std::endl;
it = next;
next = std::ranges::next(next);
}
Do not use std::xxx
to operate iterators when dealing with C 20 <ranges>
, instead, you should use ranges::xxx
, since the former is not compatible with the C 20 iterator system.