Can trim of a string be done inplace with C++20 ranges?

Inspired by cute cppreference example of trim with C++20 I have written the following code(I have changed the return type to void and arg to std::string& since my “problem”(I am inventing problems to learn C++20) does not exist in original code that uses std::string_view arg and returns std::string).

void trim(std::string&  in)
{
    auto view
        = std::views::all(in)
        | std::views::drop_while(isspace)
        | std::views::reverse
        | std::views::drop_while(isspace)
        | std::views::reverse;
        std::string result{view.begin(), view.end()};
        in = std::move(result);
}

Issue here is that this is not inplace, meaning that new string is created. I can write uglier code that does this inplace and I know that traditionally C++ algorithms have no idea that containers exist, but I wonder if C++20 has some tricks that enable me to do the trim in elegant way, but also inplace.

Here is my ugly inplace trim also(not sure if it works ok, but idea is that it does the trimming inplace):

void trim2(std::string& s) {
    // ugly and error prone, but inplace
    const auto it1 = std::ranges::find_if_not(s, isspace);
    const auto it2 = std::ranges::find_if_not(s.rbegin(), s.rend(), isspace);
    const size_t shift = (it1==s.end()) ? 0: std::distance(s.begin(), it1);
    const size_t result_size = s.size() - shift - ((it2==s.rend()) ? 0 : std::distance(s.rbegin(), it2));
    std::shift_left(s.begin(), s.end(), shift);
    s.resize(result_size);
}

godbolt

edit: originally this question claimed in.assign would be UB, but T.C. corrected me. But based on my understanding of C++23 draft assign would still cause the temporary string to be created.

Answer

Perhaps something like this?

void trim(std::string& s) {
    auto not_space = [](unsigned char c){ return !std::isspace(c); };

    // erase the the spaces at the back first
    // so we don't have to do extra work
    s.erase(
        std::ranges::find_if(s | std::views::reverse, not_space).base(),
        s.end());

    // erase the spaces at the front
    s.erase(
        s.begin(),
        std::ranges::find_if(s, not_space));
}