Home > OS >  Is there some way to use std::remove_if on std::string_view iterators?
Is there some way to use std::remove_if on std::string_view iterators?

Time:01-21

I'm wanting to effectively trim an already created std::string_view using an iterator that doesn't point to the trimmed characters thanks to std::remove_if(). However, I can't use std::remove_if() on a std::basic_string_view::iterator directly because that's really a std::basic_string_view::const_iterator and std::remove_if() can't take non-moveable iterators as arguments.

The only workaround I've though of is casting the std::string_view to a std::string and then taking the iterator. Here's an example of that:

#include <string>
#include <string_view>
#include <algorithm>
#include <locale>

int main() {
    std::string_view foo{"Whitepace...\nThe  Final    Frontier"};
    
    const auto is_space{
        [](const auto& character) {
            return std::isspace(character, std::locale{});
        }
    };
    
    // Doesn't compile
    //auto without_conversion{
    //    std::remove_if(foo.begin(), foo.end(), is_space)
    //};
    
    // Works, for the most part.
    auto with_conversion{
        std::remove_if(std::string{foo}.begin(), std::string{foo}.end(), is_space)
    };

But this kinda defeats the whole point of using std::string_view, as a string_view constructed from this iterator wouldn't be viewing the original string.

Is there some (preferably elegant) way to do this while keeping the view on the original string? Perhaps some way to make the string_view iterator non-const?

CodePudding user response:

If your goal is to trim a string_view of spaces, and store the result in a std::string, then you should choose the appropriate algorithm that allows const iterators.

One such algorithm is std::copy_if:

#include <iostream>
#include <string_view>
#include <algorithm>
#include <iterator>
#include <cctype>

int main()
{
    std::string_view foo{"Whitepace...\nThe  Final    Frontier"};
    std::string result;
    std::copy_if(foo.begin(), foo.end(), std::back_inserter(result), [](char ch) 
                { return !std::isspace(static_cast<unsigned char>(ch)); });
    std::cout << result;
}

Output:

Whitepace...TheFinalFrontier

CodePudding user response:

std::string_view is a constant view of the string sequence.

For example, begin returns a const_iterator.

https://en.cppreference.com/w/cpp/string/basic_string_view/begin

Maybe you will have better luck with std::span, however take into account that literals in the program are always immutable. You have to make a copy first anyway.

Also your last line doesn't do what you think because you are iterating over different temporaries, even if it compiles.

The correct code is, for example:

    std::string FOO = foo;
    auto with_conversion{
        std::remove_if(FOO.begin(), FOO.end(), is_space)
    };

In other words, the whole idea of your program (that you can modify a "program" string) is flawed in the first place.

  •  Tags:  
  • Related