Home > Enterprise >  Workaround to decrement iterator from views::transform?
Workaround to decrement iterator from views::transform?

Time:01-06

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);
}

Demo

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.

  • Related